Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
solo
Project overview
Project overview
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
solo
Commits
4af1a1bb
Commit
4af1a1bb
authored
Jun 27, 2012
by
Liang Ding
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
c
parent
2afd5b47
Changes
17
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
4157 additions
and
4142 deletions
+4157
-4142
core/src/main/java/org/b3log/solo/processor/FeedProcessor.java
...src/main/java/org/b3log/solo/processor/FeedProcessor.java
+516
-515
core/src/main/java/org/b3log/solo/processor/SitemapProcessor.java
.../main/java/org/b3log/solo/processor/SitemapProcessor.java
+243
-242
core/src/main/java/org/b3log/solo/processor/util/Filler.java
core/src/main/java/org/b3log/solo/processor/util/Filler.java
+899
-901
core/src/main/java/org/b3log/solo/repository/impl/ArchiveDateArticleRepositoryImpl.java
...olo/repository/impl/ArchiveDateArticleRepositoryImpl.java
+86
-90
core/src/main/java/org/b3log/solo/repository/impl/ArchiveDateRepositoryImpl.java
...b3log/solo/repository/impl/ArchiveDateRepositoryImpl.java
+120
-124
core/src/main/java/org/b3log/solo/repository/impl/ArticleRepositoryImpl.java
...org/b3log/solo/repository/impl/ArticleRepositoryImpl.java
+268
-260
core/src/main/java/org/b3log/solo/repository/impl/CommentRepositoryImpl.java
...org/b3log/solo/repository/impl/CommentRepositoryImpl.java
+164
-168
core/src/main/java/org/b3log/solo/repository/impl/LinkRepositoryImpl.java
...va/org/b3log/solo/repository/impl/LinkRepositoryImpl.java
+154
-156
core/src/main/java/org/b3log/solo/repository/impl/PageRepositoryImpl.java
...va/org/b3log/solo/repository/impl/PageRepositoryImpl.java
+161
-161
core/src/main/java/org/b3log/solo/repository/impl/TagArticleRepositoryImpl.java
.../b3log/solo/repository/impl/TagArticleRepositoryImpl.java
+89
-91
core/src/main/java/org/b3log/solo/repository/impl/TagRepositoryImpl.java
...ava/org/b3log/solo/repository/impl/TagRepositoryImpl.java
+112
-115
core/src/main/java/org/b3log/solo/repository/impl/UserRepositoryImpl.java
...va/org/b3log/solo/repository/impl/UserRepositoryImpl.java
+103
-104
core/src/main/java/org/b3log/solo/service/ArticleQueryService.java
...main/java/org/b3log/solo/service/ArticleQueryService.java
+809
-806
core/src/main/java/org/b3log/solo/util/Articles.java
core/src/main/java/org/b3log/solo/util/Articles.java
+303
-305
core/src/test/java/org/b3log/solo/repository/impl/UserRepositoryImplTestCase.java
...3log/solo/repository/impl/UserRepositoryImplTestCase.java
+102
-102
core/src/test/resources/skins/ease/skin.properties
core/src/test/resources/skins/ease/skin.properties
+26
-0
pom.xml
pom.xml
+2
-2
No files found.
core/src/main/java/org/b3log/solo/processor/FeedProcessor.java
View file @
4af1a1bb
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
processor
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.Date
;
import
java.util.List
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
org.apache.commons.lang.StringEscapeUtils
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.annotation.RequestProcessing
;
import
org.b3log.latke.annotation.RequestProcessor
;
import
org.b3log.latke.model.User
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.Query
;
import
org.b3log.latke.repository.SortDirection
;
import
org.b3log.latke.servlet.HTTPRequestContext
;
import
org.b3log.latke.servlet.HTTPRequestMethod
;
import
org.b3log.latke.servlet.renderer.AtomRenderer
;
import
org.b3log.latke.servlet.renderer.RssRenderer
;
import
org.b3log.latke.util.Locales
;
import
org.b3log.latke.util.Strings
;
import
org.b3log.solo.SoloServletListener
;
import
org.b3log.solo.model.Article
;
import
org.b3log.solo.model.Preference
;
import
org.b3log.solo.model.Tag
;
import
org.b3log.solo.model.feed.atom.Category
;
import
org.b3log.solo.model.feed.atom.Entry
;
import
org.b3log.solo.model.feed.atom.Feed
;
import
org.b3log.solo.model.feed.rss.Channel
;
import
org.b3log.solo.model.feed.rss.Item
;
import
org.b3log.solo.repository.ArticleRepository
;
import
org.b3log.solo.repository.TagArticleRepository
;
import
org.b3log.solo.repository.TagRepository
;
import
org.b3log.solo.repository.impl.ArticleRepositoryImpl
;
import
org.b3log.solo.repository.impl.TagArticleRepositoryImpl
;
import
org.b3log.solo.repository.impl.TagRepositoryImpl
;
import
org.b3log.solo.service.PreferenceQueryService
;
import
org.b3log.solo.util.Articles
;
import
org.b3log.solo.util.TimeZones
;
import
org.b3log.solo.util.Users
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Feed (Atom/RSS) processor.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.1.0.0, May 10, 2012
* @since 0.3.1
*/
@RequestProcessor
public
final
class
FeedProcessor
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
FeedProcessor
.
class
.
getName
());
/**
* Article repository.
*/
private
ArticleRepository
articleRepository
=
ArticleRepositoryImpl
.
getInstance
();
/**
* Preference query service.
*/
private
PreferenceQueryService
preferenceQueryService
=
PreferenceQueryService
.
getInstance
();
/**
* Count of output entry.
*/
public
static
final
int
ENTRY_OUTPUT_CNT
=
10
;
/**
* Article utilities.
*/
private
Articles
articleUtils
=
Articles
.
getInstance
();
/**
* Tag repository.
*/
private
TagRepository
tagRepository
=
TagRepositoryImpl
.
getInstance
();
/**
* Tag-Article repository.
*/
private
TagArticleRepository
tagArticleRepository
=
TagArticleRepositoryImpl
.
getInstance
();
/**
* Blog articles Atom output.
*
* @param context the specified context
*/
@RequestProcessing
(
value
=
{
"/blog-articles-feed.do"
},
method
=
{
HTTPRequestMethod
.
GET
,
HTTPRequestMethod
.
HEAD
})
public
void
blogArticlesAtom
(
final
HTTPRequestContext
context
)
{
final
AtomRenderer
renderer
=
new
AtomRenderer
();
context
.
setRenderer
(
renderer
);
final
Feed
feed
=
new
Feed
();
try
{
final
JSONObject
preference
=
preferenceQueryService
.
getPreference
();
final
String
blogTitle
=
preference
.
getString
(
Preference
.
BLOG_TITLE
);
final
String
blogSubtitle
=
preference
.
getString
(
Preference
.
BLOG_SUBTITLE
);
final
String
blogHost
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
feed
.
setTitle
(
StringEscapeUtils
.
escapeXml
(
blogTitle
));
feed
.
setSubtitle
(
StringEscapeUtils
.
escapeXml
(
blogSubtitle
));
feed
.
setUpdated
(
TimeZones
.
getTime
(
preference
.
getString
(
Preference
.
TIME_ZONE_ID
)));
feed
.
setAuthor
(
StringEscapeUtils
.
escapeXml
(
blogTitle
));
feed
.
setLink
(
"http://"
+
blogHost
+
"/blog-articles-feed.do"
);
feed
.
setId
(
"http://"
+
blogHost
+
"/"
);
final
Query
query
=
new
Query
().
setCurrentPageNum
(
1
).
setPageSize
(
ENTRY_OUTPUT_CNT
).
addFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
).
addSort
(
Article
.
ARTICLE_UPDATE_DATE
,
SortDirection
.
DESCENDING
).
setPageCount
(
1
);
final
boolean
hasMultipleUsers
=
Users
.
getInstance
().
hasMultipleUsers
();
String
authorName
=
""
;
final
JSONObject
articleResult
=
articleRepository
.
get
(
query
);
final
JSONArray
articles
=
articleResult
.
getJSONArray
(
Keys
.
RESULTS
);
if
(!
hasMultipleUsers
&&
0
!=
articles
.
length
())
{
authorName
=
articleUtils
.
getAuthor
(
articles
.
getJSONObject
(
0
)).
getString
(
User
.
USER_NAME
);
}
final
boolean
isFullContent
=
"fullContent"
.
equals
(
preference
.
getString
(
Preference
.
FEED_OUTPUT_MODE
));
for
(
int
i
=
0
;
i
<
articles
.
length
();
i
++)
{
final
JSONObject
article
=
articles
.
getJSONObject
(
i
);
final
Entry
entry
=
new
Entry
();
feed
.
addEntry
(
entry
);
final
String
title
=
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_TITLE
));
entry
.
setTitle
(
title
);
final
String
summary
=
isFullContent
?
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_CONTENT
))
:
StringEscapeUtils
.
escapeXml
(
article
.
optString
(
Article
.
ARTICLE_ABSTRACT
));
entry
.
setSummary
(
summary
);
final
Date
updated
=
(
Date
)
article
.
get
(
Article
.
ARTICLE_UPDATE_DATE
);
entry
.
setUpdated
(
updated
);
final
String
link
=
"http://"
+
blogHost
+
article
.
getString
(
Article
.
ARTICLE_PERMALINK
);
entry
.
setLink
(
link
);
entry
.
setId
(
link
);
if
(
hasMultipleUsers
)
{
authorName
=
StringEscapeUtils
.
escapeXml
(
articleUtils
.
getAuthor
(
article
).
getString
(
User
.
USER_NAME
));
}
entry
.
setAuthor
(
authorName
);
final
String
tagsString
=
article
.
getString
(
Article
.
ARTICLE_TAGS_REF
);
final
String
[]
tagStrings
=
tagsString
.
split
(
","
);
for
(
int
j
=
0
;
j
<
tagStrings
.
length
;
j
++)
{
final
Category
catetory
=
new
Category
();
entry
.
addCatetory
(
catetory
);
final
String
tag
=
tagStrings
[
j
];
catetory
.
setTerm
(
tag
);
}
}
renderer
.
setContent
(
feed
.
toString
());
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Get blog article feed error"
,
e
);
try
{
context
.
getResponse
().
sendError
(
HttpServletResponse
.
SC_SERVICE_UNAVAILABLE
);
}
catch
(
final
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
}
/**
* Tag articles Atom output.
*
* @param context the specified context
* @throws IOException io exception
*/
@RequestProcessing
(
value
=
{
"/tag-articles-feed.do"
},
method
=
{
HTTPRequestMethod
.
GET
,
HTTPRequestMethod
.
HEAD
})
public
void
tagArticlesAtom
(
final
HTTPRequestContext
context
)
throws
IOException
{
final
AtomRenderer
renderer
=
new
AtomRenderer
();
context
.
setRenderer
(
renderer
);
final
HttpServletRequest
request
=
context
.
getRequest
();
final
HttpServletResponse
response
=
context
.
getResponse
();
final
String
queryString
=
request
.
getQueryString
();
if
(
Strings
.
isEmptyOrNull
(
queryString
))
{
response
.
sendError
(
HttpServletResponse
.
SC_BAD_REQUEST
);
return
;
}
final
String
oIdMap
=
queryString
.
split
(
"&"
)[
0
];
final
String
tagId
=
oIdMap
.
split
(
"="
)[
1
];
final
Feed
feed
=
new
Feed
();
try
{
final
String
tagTitle
=
tagRepository
.
get
(
tagId
).
getString
(
Tag
.
TAG_TITLE
);
final
JSONObject
preference
=
preferenceQueryService
.
getPreference
();
if
(
null
==
preference
)
{
response
.
sendError
(
HttpServletResponse
.
SC_NOT_FOUND
);
return
;
}
final
String
blogTitle
=
preference
.
getString
(
Preference
.
BLOG_TITLE
);
final
String
blogSubtitle
=
preference
.
getString
(
Preference
.
BLOG_SUBTITLE
)
+
", "
+
tagTitle
;
final
String
blogHost
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
feed
.
setTitle
(
StringEscapeUtils
.
escapeXml
(
blogTitle
));
feed
.
setSubtitle
(
StringEscapeUtils
.
escapeXml
(
blogSubtitle
));
feed
.
setUpdated
(
TimeZones
.
getTime
(
preference
.
getString
(
Preference
.
TIME_ZONE_ID
)));
feed
.
setAuthor
(
StringEscapeUtils
.
escapeXml
(
blogTitle
));
feed
.
setLink
(
"http://"
+
blogHost
+
"/tag-articles-feed.do"
);
feed
.
setId
(
"http://"
+
blogHost
+
"/"
);
final
JSONObject
tagArticleResult
=
tagArticleRepository
.
getByTagId
(
tagId
,
1
,
ENTRY_OUTPUT_CNT
);
final
JSONArray
tagArticleRelations
=
tagArticleResult
.
getJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
tagArticleRelations
.
length
())
{
response
.
sendError
(
HttpServletResponse
.
SC_NOT_FOUND
);
return
;
}
final
List
<
JSONObject
>
articles
=
new
ArrayList
<
JSONObject
>();
for
(
int
i
=
0
;
i
<
tagArticleRelations
.
length
();
i
++)
{
final
JSONObject
tagArticleRelation
=
tagArticleRelations
.
getJSONObject
(
i
);
final
String
articleId
=
tagArticleRelation
.
getString
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
);
final
JSONObject
article
=
articleRepository
.
get
(
articleId
);
if
(
article
.
getBoolean
(
Article
.
ARTICLE_IS_PUBLISHED
))
{
// Skips the unpublished article
articles
.
add
(
article
);
}
}
final
boolean
hasMultipleUsers
=
Users
.
getInstance
().
hasMultipleUsers
();
String
authorName
=
""
;
if
(!
hasMultipleUsers
&&
!
articles
.
isEmpty
())
{
authorName
=
articleUtils
.
getAuthor
(
articles
.
get
(
0
)).
getString
(
User
.
USER_NAME
);
}
final
boolean
isFullContent
=
"fullContent"
.
equals
(
preference
.
getString
(
Preference
.
FEED_OUTPUT_MODE
));
for
(
int
i
=
0
;
i
<
articles
.
size
();
i
++)
{
final
JSONObject
article
=
articles
.
get
(
i
);
final
Entry
entry
=
new
Entry
();
feed
.
addEntry
(
entry
);
final
String
title
=
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_TITLE
));
entry
.
setTitle
(
title
);
final
String
summary
=
isFullContent
?
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_CONTENT
))
:
StringEscapeUtils
.
escapeXml
(
article
.
optString
(
Article
.
ARTICLE_ABSTRACT
));
entry
.
setSummary
(
summary
);
final
Date
updated
=
(
Date
)
article
.
get
(
Article
.
ARTICLE_UPDATE_DATE
);
entry
.
setUpdated
(
updated
);
final
String
link
=
"http://"
+
blogHost
+
article
.
getString
(
Article
.
ARTICLE_PERMALINK
);
entry
.
setLink
(
link
);
entry
.
setId
(
link
);
if
(
hasMultipleUsers
)
{
authorName
=
StringEscapeUtils
.
escapeXml
(
articleUtils
.
getAuthor
(
article
).
getString
(
User
.
USER_NAME
));
}
entry
.
setAuthor
(
authorName
);
final
String
tagsString
=
article
.
getString
(
Article
.
ARTICLE_TAGS_REF
);
final
String
[]
tagStrings
=
tagsString
.
split
(
","
);
for
(
int
j
=
0
;
j
<
tagStrings
.
length
;
j
++)
{
final
Category
catetory
=
new
Category
();
entry
.
addCatetory
(
catetory
);
final
String
tag
=
tagStrings
[
j
];
catetory
.
setTerm
(
tag
);
}
}
renderer
.
setContent
(
feed
.
toString
());
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Get tag article feed error"
,
e
);
try
{
context
.
getResponse
().
sendError
(
HttpServletResponse
.
SC_SERVICE_UNAVAILABLE
);
}
catch
(
final
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
}
/**
* Blog articles RSS output.
*
* @param context the specified context
*/
@RequestProcessing
(
value
=
{
"/blog-articles-rss.do"
},
method
=
{
HTTPRequestMethod
.
GET
,
HTTPRequestMethod
.
HEAD
})
public
void
blogArticlesRSS
(
final
HTTPRequestContext
context
)
{
final
HttpServletResponse
response
=
context
.
getResponse
();
final
RssRenderer
renderer
=
new
RssRenderer
();
context
.
setRenderer
(
renderer
);
final
Channel
channel
=
new
Channel
();
try
{
final
JSONObject
preference
=
preferenceQueryService
.
getPreference
();
if
(
null
==
preference
)
{
response
.
sendError
(
HttpServletResponse
.
SC_NOT_FOUND
);
return
;
}
final
String
blogTitle
=
preference
.
getString
(
Preference
.
BLOG_TITLE
);
final
String
blogSubtitle
=
preference
.
getString
(
Preference
.
BLOG_SUBTITLE
);
final
String
blogHost
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
channel
.
setTitle
(
StringEscapeUtils
.
escapeXml
(
blogTitle
));
channel
.
setLastBuildDate
(
TimeZones
.
getTime
(
preference
.
getString
(
Preference
.
TIME_ZONE_ID
)));
channel
.
setLink
(
"http://"
+
blogHost
);
channel
.
setAtomLink
(
"http://"
+
blogHost
+
"/blog-articles-rss.do"
);
channel
.
setGenerator
(
"B3log Solo, ver "
+
SoloServletListener
.
VERSION
);
final
String
localeString
=
preference
.
getString
(
Preference
.
LOCALE_STRING
);
final
String
country
=
Locales
.
getCountry
(
localeString
).
toLowerCase
();
final
String
language
=
Locales
.
getLanguage
(
localeString
).
toLowerCase
();
channel
.
setLanguage
(
language
+
'-'
+
country
);
channel
.
setDescription
(
blogSubtitle
);
final
Query
query
=
new
Query
().
setCurrentPageNum
(
1
).
setPageSize
(
ENTRY_OUTPUT_CNT
).
addFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
).
addSort
(
Article
.
ARTICLE_UPDATE_DATE
,
SortDirection
.
DESCENDING
).
setPageCount
(
1
);
final
JSONObject
articleResult
=
articleRepository
.
get
(
query
);
final
JSONArray
articles
=
articleResult
.
getJSONArray
(
Keys
.
RESULTS
);
final
boolean
hasMultipleUsers
=
Users
.
getInstance
().
hasMultipleUsers
();
String
authorName
=
""
;
if
(!
hasMultipleUsers
&&
0
!=
articles
.
length
())
{
authorName
=
articleUtils
.
getAuthor
(
articles
.
getJSONObject
(
0
)).
getString
(
User
.
USER_NAME
);
}
final
boolean
isFullContent
=
"fullContent"
.
equals
(
preference
.
getString
(
Preference
.
FEED_OUTPUT_MODE
));
for
(
int
i
=
0
;
i
<
articles
.
length
();
i
++)
{
final
JSONObject
article
=
articles
.
getJSONObject
(
i
);
final
Item
item
=
new
Item
();
channel
.
addItem
(
item
);
final
String
title
=
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_TITLE
));
item
.
setTitle
(
title
);
final
String
description
=
isFullContent
?
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_CONTENT
))
:
StringEscapeUtils
.
escapeXml
(
article
.
optString
(
Article
.
ARTICLE_ABSTRACT
));
item
.
setDescription
(
description
);
final
Date
pubDate
=
(
Date
)
article
.
get
(
Article
.
ARTICLE_UPDATE_DATE
);
item
.
setPubDate
(
pubDate
);
final
String
link
=
"http://"
+
blogHost
+
article
.
getString
(
Article
.
ARTICLE_PERMALINK
);
item
.
setLink
(
link
);
item
.
setGUID
(
link
);
final
String
authorEmail
=
article
.
getString
(
Article
.
ARTICLE_AUTHOR_EMAIL
);
if
(
hasMultipleUsers
)
{
authorName
=
StringEscapeUtils
.
escapeXml
(
articleUtils
.
getAuthor
(
article
).
getString
(
User
.
USER_NAME
));
}
item
.
setAuthor
(
authorEmail
+
"("
+
authorName
+
")"
);
final
String
tagsString
=
article
.
getString
(
Article
.
ARTICLE_TAGS_REF
);
final
String
[]
tagStrings
=
tagsString
.
split
(
","
);
for
(
int
j
=
0
;
j
<
tagStrings
.
length
;
j
++)
{
final
org
.
b3log
.
solo
.
model
.
feed
.
rss
.
Category
catetory
=
new
org
.
b3log
.
solo
.
model
.
feed
.
rss
.
Category
();
item
.
addCatetory
(
catetory
);
final
String
tag
=
tagStrings
[
j
];
catetory
.
setTerm
(
tag
);
}
}
renderer
.
setContent
(
channel
.
toString
());
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Get blog article rss error"
,
e
);
try
{
context
.
getResponse
().
sendError
(
HttpServletResponse
.
SC_SERVICE_UNAVAILABLE
);
}
catch
(
final
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
}
/**
* Tag articles RSS output.
*
* @param context the specified context
* @throws IOException io exception
*/
@RequestProcessing
(
value
=
{
"/tag-articles-rss.do"
},
method
=
{
HTTPRequestMethod
.
GET
,
HTTPRequestMethod
.
HEAD
})
public
void
tagArticlesRSS
(
final
HTTPRequestContext
context
)
throws
IOException
{
final
HttpServletResponse
response
=
context
.
getResponse
();
final
HttpServletRequest
request
=
context
.
getRequest
();
final
RssRenderer
renderer
=
new
RssRenderer
();
context
.
setRenderer
(
renderer
);
final
String
queryString
=
request
.
getQueryString
();
if
(
Strings
.
isEmptyOrNull
(
queryString
))
{
response
.
sendError
(
HttpServletResponse
.
SC_BAD_REQUEST
);
return
;
}
final
String
oIdMap
=
queryString
.
split
(
"&"
)[
0
];
final
String
tagId
=
oIdMap
.
split
(
"="
)[
1
];
final
Channel
channel
=
new
Channel
();
try
{
final
String
tagTitle
=
tagRepository
.
get
(
tagId
).
getString
(
Tag
.
TAG_TITLE
);
final
JSONObject
preference
=
preferenceQueryService
.
getPreference
();
if
(
null
==
preference
)
{
response
.
sendError
(
HttpServletResponse
.
SC_NOT_FOUND
);
return
;
}
final
String
blogTitle
=
preference
.
getString
(
Preference
.
BLOG_TITLE
);
final
String
blogSubtitle
=
preference
.
getString
(
Preference
.
BLOG_SUBTITLE
)
+
", "
+
tagTitle
;
final
String
blogHost
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
channel
.
setTitle
(
StringEscapeUtils
.
escapeXml
(
blogTitle
));
channel
.
setLastBuildDate
(
TimeZones
.
getTime
(
preference
.
getString
(
Preference
.
TIME_ZONE_ID
)));
channel
.
setLink
(
"http://"
+
blogHost
);
channel
.
setAtomLink
(
"http://"
+
blogHost
+
"/tag-articles-rss.do"
);
channel
.
setGenerator
(
"B3log Solo, ver "
+
SoloServletListener
.
VERSION
);
final
String
localeString
=
preference
.
getString
(
Preference
.
LOCALE_STRING
);
final
String
country
=
Locales
.
getCountry
(
localeString
).
toLowerCase
();
final
String
language
=
Locales
.
getLanguage
(
localeString
).
toLowerCase
();
channel
.
setLanguage
(
language
+
'-'
+
country
);
channel
.
setDescription
(
blogSubtitle
);
final
JSONObject
tagArticleResult
=
tagArticleRepository
.
getByTagId
(
tagId
,
1
,
ENTRY_OUTPUT_CNT
);
final
JSONArray
tagArticleRelations
=
tagArticleResult
.
getJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
tagArticleRelations
.
length
())
{
response
.
sendError
(
HttpServletResponse
.
SC_NOT_FOUND
);
return
;
}
final
List
<
JSONObject
>
articles
=
new
ArrayList
<
JSONObject
>();
for
(
int
i
=
0
;
i
<
tagArticleRelations
.
length
();
i
++)
{
final
JSONObject
tagArticleRelation
=
tagArticleRelations
.
getJSONObject
(
i
);
final
String
articleId
=
tagArticleRelation
.
getString
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
);
final
JSONObject
article
=
articleRepository
.
get
(
articleId
);
if
(
article
.
getBoolean
(
Article
.
ARTICLE_IS_PUBLISHED
))
{
// Skips the unpublished article
articles
.
add
(
article
);
}
}
final
boolean
hasMultipleUsers
=
Users
.
getInstance
().
hasMultipleUsers
();
String
authorName
=
""
;
if
(!
hasMultipleUsers
&&
!
articles
.
isEmpty
())
{
authorName
=
articleUtils
.
getAuthor
(
articles
.
get
(
0
)).
getString
(
User
.
USER_NAME
);
}
final
boolean
isFullContent
=
"fullContent"
.
equals
(
preference
.
getString
(
Preference
.
FEED_OUTPUT_MODE
));
for
(
int
i
=
0
;
i
<
articles
.
size
();
i
++)
{
final
JSONObject
article
=
articles
.
get
(
i
);
final
Item
item
=
new
Item
();
channel
.
addItem
(
item
);
final
String
title
=
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_TITLE
));
item
.
setTitle
(
title
);
final
String
description
=
isFullContent
?
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_CONTENT
))
:
StringEscapeUtils
.
escapeXml
(
article
.
optString
(
Article
.
ARTICLE_ABSTRACT
));
item
.
setDescription
(
description
);
final
Date
pubDate
=
(
Date
)
article
.
get
(
Article
.
ARTICLE_UPDATE_DATE
);
item
.
setPubDate
(
pubDate
);
final
String
link
=
"http://"
+
blogHost
+
article
.
getString
(
Article
.
ARTICLE_PERMALINK
);
item
.
setLink
(
link
);
item
.
setGUID
(
link
);
final
String
authorEmail
=
article
.
getString
(
Article
.
ARTICLE_AUTHOR_EMAIL
);
if
(
hasMultipleUsers
)
{
authorName
=
StringEscapeUtils
.
escapeXml
(
articleUtils
.
getAuthor
(
article
).
getString
(
User
.
USER_NAME
));
}
item
.
setAuthor
(
authorEmail
+
"("
+
authorName
+
")"
);
final
String
tagsString
=
article
.
getString
(
Article
.
ARTICLE_TAGS_REF
);
final
String
[]
tagStrings
=
tagsString
.
split
(
","
);
for
(
int
j
=
0
;
j
<
tagStrings
.
length
;
j
++)
{
final
org
.
b3log
.
solo
.
model
.
feed
.
rss
.
Category
catetory
=
new
org
.
b3log
.
solo
.
model
.
feed
.
rss
.
Category
();
item
.
addCatetory
(
catetory
);
final
String
tag
=
tagStrings
[
j
];
catetory
.
setTerm
(
tag
);
}
}
renderer
.
setContent
(
channel
.
toString
());
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Get tag article rss error"
,
e
);
try
{
context
.
getResponse
().
sendError
(
HttpServletResponse
.
SC_SERVICE_UNAVAILABLE
);
}
catch
(
final
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
processor
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.Date
;
import
java.util.List
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
org.apache.commons.lang.StringEscapeUtils
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.annotation.RequestProcessing
;
import
org.b3log.latke.annotation.RequestProcessor
;
import
org.b3log.latke.model.User
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.PropertyFilter
;
import
org.b3log.latke.repository.Query
;
import
org.b3log.latke.repository.SortDirection
;
import
org.b3log.latke.servlet.HTTPRequestContext
;
import
org.b3log.latke.servlet.HTTPRequestMethod
;
import
org.b3log.latke.servlet.renderer.AtomRenderer
;
import
org.b3log.latke.servlet.renderer.RssRenderer
;
import
org.b3log.latke.util.Locales
;
import
org.b3log.latke.util.Strings
;
import
org.b3log.solo.SoloServletListener
;
import
org.b3log.solo.model.Article
;
import
org.b3log.solo.model.Preference
;
import
org.b3log.solo.model.Tag
;
import
org.b3log.solo.model.feed.atom.Category
;
import
org.b3log.solo.model.feed.atom.Entry
;
import
org.b3log.solo.model.feed.atom.Feed
;
import
org.b3log.solo.model.feed.rss.Channel
;
import
org.b3log.solo.model.feed.rss.Item
;
import
org.b3log.solo.repository.ArticleRepository
;
import
org.b3log.solo.repository.TagArticleRepository
;
import
org.b3log.solo.repository.TagRepository
;
import
org.b3log.solo.repository.impl.ArticleRepositoryImpl
;
import
org.b3log.solo.repository.impl.TagArticleRepositoryImpl
;
import
org.b3log.solo.repository.impl.TagRepositoryImpl
;
import
org.b3log.solo.service.PreferenceQueryService
;
import
org.b3log.solo.util.Articles
;
import
org.b3log.solo.util.TimeZones
;
import
org.b3log.solo.util.Users
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Feed (Atom/RSS) processor.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.1.0.0, May 10, 2012
* @since 0.3.1
*/
@RequestProcessor
public
final
class
FeedProcessor
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
FeedProcessor
.
class
.
getName
());
/**
* Article repository.
*/
private
ArticleRepository
articleRepository
=
ArticleRepositoryImpl
.
getInstance
();
/**
* Preference query service.
*/
private
PreferenceQueryService
preferenceQueryService
=
PreferenceQueryService
.
getInstance
();
/**
* Count of output entry.
*/
public
static
final
int
ENTRY_OUTPUT_CNT
=
10
;
/**
* Article utilities.
*/
private
Articles
articleUtils
=
Articles
.
getInstance
();
/**
* Tag repository.
*/
private
TagRepository
tagRepository
=
TagRepositoryImpl
.
getInstance
();
/**
* Tag-Article repository.
*/
private
TagArticleRepository
tagArticleRepository
=
TagArticleRepositoryImpl
.
getInstance
();
/**
* Blog articles Atom output.
*
* @param context the specified context
*/
@RequestProcessing
(
value
=
{
"/blog-articles-feed.do"
},
method
=
{
HTTPRequestMethod
.
GET
,
HTTPRequestMethod
.
HEAD
})
public
void
blogArticlesAtom
(
final
HTTPRequestContext
context
)
{
final
AtomRenderer
renderer
=
new
AtomRenderer
();
context
.
setRenderer
(
renderer
);
final
Feed
feed
=
new
Feed
();
try
{
final
JSONObject
preference
=
preferenceQueryService
.
getPreference
();
final
String
blogTitle
=
preference
.
getString
(
Preference
.
BLOG_TITLE
);
final
String
blogSubtitle
=
preference
.
getString
(
Preference
.
BLOG_SUBTITLE
);
final
String
blogHost
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
feed
.
setTitle
(
StringEscapeUtils
.
escapeXml
(
blogTitle
));
feed
.
setSubtitle
(
StringEscapeUtils
.
escapeXml
(
blogSubtitle
));
feed
.
setUpdated
(
TimeZones
.
getTime
(
preference
.
getString
(
Preference
.
TIME_ZONE_ID
)));
feed
.
setAuthor
(
StringEscapeUtils
.
escapeXml
(
blogTitle
));
feed
.
setLink
(
"http://"
+
blogHost
+
"/blog-articles-feed.do"
);
feed
.
setId
(
"http://"
+
blogHost
+
"/"
);
final
Query
query
=
new
Query
().
setCurrentPageNum
(
1
).
setPageSize
(
ENTRY_OUTPUT_CNT
).
setFilter
(
new
PropertyFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
)).
addSort
(
Article
.
ARTICLE_UPDATE_DATE
,
SortDirection
.
DESCENDING
).
setPageCount
(
1
);
final
boolean
hasMultipleUsers
=
Users
.
getInstance
().
hasMultipleUsers
();
String
authorName
=
""
;
final
JSONObject
articleResult
=
articleRepository
.
get
(
query
);
final
JSONArray
articles
=
articleResult
.
getJSONArray
(
Keys
.
RESULTS
);
if
(!
hasMultipleUsers
&&
0
!=
articles
.
length
())
{
authorName
=
articleUtils
.
getAuthor
(
articles
.
getJSONObject
(
0
)).
getString
(
User
.
USER_NAME
);
}
final
boolean
isFullContent
=
"fullContent"
.
equals
(
preference
.
getString
(
Preference
.
FEED_OUTPUT_MODE
));
for
(
int
i
=
0
;
i
<
articles
.
length
();
i
++)
{
final
JSONObject
article
=
articles
.
getJSONObject
(
i
);
final
Entry
entry
=
new
Entry
();
feed
.
addEntry
(
entry
);
final
String
title
=
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_TITLE
));
entry
.
setTitle
(
title
);
final
String
summary
=
isFullContent
?
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_CONTENT
))
:
StringEscapeUtils
.
escapeXml
(
article
.
optString
(
Article
.
ARTICLE_ABSTRACT
));
entry
.
setSummary
(
summary
);
final
Date
updated
=
(
Date
)
article
.
get
(
Article
.
ARTICLE_UPDATE_DATE
);
entry
.
setUpdated
(
updated
);
final
String
link
=
"http://"
+
blogHost
+
article
.
getString
(
Article
.
ARTICLE_PERMALINK
);
entry
.
setLink
(
link
);
entry
.
setId
(
link
);
if
(
hasMultipleUsers
)
{
authorName
=
StringEscapeUtils
.
escapeXml
(
articleUtils
.
getAuthor
(
article
).
getString
(
User
.
USER_NAME
));
}
entry
.
setAuthor
(
authorName
);
final
String
tagsString
=
article
.
getString
(
Article
.
ARTICLE_TAGS_REF
);
final
String
[]
tagStrings
=
tagsString
.
split
(
","
);
for
(
int
j
=
0
;
j
<
tagStrings
.
length
;
j
++)
{
final
Category
catetory
=
new
Category
();
entry
.
addCatetory
(
catetory
);
final
String
tag
=
tagStrings
[
j
];
catetory
.
setTerm
(
tag
);
}
}
renderer
.
setContent
(
feed
.
toString
());
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Get blog article feed error"
,
e
);
try
{
context
.
getResponse
().
sendError
(
HttpServletResponse
.
SC_SERVICE_UNAVAILABLE
);
}
catch
(
final
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
}
/**
* Tag articles Atom output.
*
* @param context the specified context
* @throws IOException io exception
*/
@RequestProcessing
(
value
=
{
"/tag-articles-feed.do"
},
method
=
{
HTTPRequestMethod
.
GET
,
HTTPRequestMethod
.
HEAD
})
public
void
tagArticlesAtom
(
final
HTTPRequestContext
context
)
throws
IOException
{
final
AtomRenderer
renderer
=
new
AtomRenderer
();
context
.
setRenderer
(
renderer
);
final
HttpServletRequest
request
=
context
.
getRequest
();
final
HttpServletResponse
response
=
context
.
getResponse
();
final
String
queryString
=
request
.
getQueryString
();
if
(
Strings
.
isEmptyOrNull
(
queryString
))
{
response
.
sendError
(
HttpServletResponse
.
SC_BAD_REQUEST
);
return
;
}
final
String
oIdMap
=
queryString
.
split
(
"&"
)[
0
];
final
String
tagId
=
oIdMap
.
split
(
"="
)[
1
];
final
Feed
feed
=
new
Feed
();
try
{
final
String
tagTitle
=
tagRepository
.
get
(
tagId
).
getString
(
Tag
.
TAG_TITLE
);
final
JSONObject
preference
=
preferenceQueryService
.
getPreference
();
if
(
null
==
preference
)
{
response
.
sendError
(
HttpServletResponse
.
SC_NOT_FOUND
);
return
;
}
final
String
blogTitle
=
preference
.
getString
(
Preference
.
BLOG_TITLE
);
final
String
blogSubtitle
=
preference
.
getString
(
Preference
.
BLOG_SUBTITLE
)
+
", "
+
tagTitle
;
final
String
blogHost
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
feed
.
setTitle
(
StringEscapeUtils
.
escapeXml
(
blogTitle
));
feed
.
setSubtitle
(
StringEscapeUtils
.
escapeXml
(
blogSubtitle
));
feed
.
setUpdated
(
TimeZones
.
getTime
(
preference
.
getString
(
Preference
.
TIME_ZONE_ID
)));
feed
.
setAuthor
(
StringEscapeUtils
.
escapeXml
(
blogTitle
));
feed
.
setLink
(
"http://"
+
blogHost
+
"/tag-articles-feed.do"
);
feed
.
setId
(
"http://"
+
blogHost
+
"/"
);
final
JSONObject
tagArticleResult
=
tagArticleRepository
.
getByTagId
(
tagId
,
1
,
ENTRY_OUTPUT_CNT
);
final
JSONArray
tagArticleRelations
=
tagArticleResult
.
getJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
tagArticleRelations
.
length
())
{
response
.
sendError
(
HttpServletResponse
.
SC_NOT_FOUND
);
return
;
}
final
List
<
JSONObject
>
articles
=
new
ArrayList
<
JSONObject
>();
for
(
int
i
=
0
;
i
<
tagArticleRelations
.
length
();
i
++)
{
final
JSONObject
tagArticleRelation
=
tagArticleRelations
.
getJSONObject
(
i
);
final
String
articleId
=
tagArticleRelation
.
getString
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
);
final
JSONObject
article
=
articleRepository
.
get
(
articleId
);
if
(
article
.
getBoolean
(
Article
.
ARTICLE_IS_PUBLISHED
))
{
// Skips the unpublished article
articles
.
add
(
article
);
}
}
final
boolean
hasMultipleUsers
=
Users
.
getInstance
().
hasMultipleUsers
();
String
authorName
=
""
;
if
(!
hasMultipleUsers
&&
!
articles
.
isEmpty
())
{
authorName
=
articleUtils
.
getAuthor
(
articles
.
get
(
0
)).
getString
(
User
.
USER_NAME
);
}
final
boolean
isFullContent
=
"fullContent"
.
equals
(
preference
.
getString
(
Preference
.
FEED_OUTPUT_MODE
));
for
(
int
i
=
0
;
i
<
articles
.
size
();
i
++)
{
final
JSONObject
article
=
articles
.
get
(
i
);
final
Entry
entry
=
new
Entry
();
feed
.
addEntry
(
entry
);
final
String
title
=
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_TITLE
));
entry
.
setTitle
(
title
);
final
String
summary
=
isFullContent
?
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_CONTENT
))
:
StringEscapeUtils
.
escapeXml
(
article
.
optString
(
Article
.
ARTICLE_ABSTRACT
));
entry
.
setSummary
(
summary
);
final
Date
updated
=
(
Date
)
article
.
get
(
Article
.
ARTICLE_UPDATE_DATE
);
entry
.
setUpdated
(
updated
);
final
String
link
=
"http://"
+
blogHost
+
article
.
getString
(
Article
.
ARTICLE_PERMALINK
);
entry
.
setLink
(
link
);
entry
.
setId
(
link
);
if
(
hasMultipleUsers
)
{
authorName
=
StringEscapeUtils
.
escapeXml
(
articleUtils
.
getAuthor
(
article
).
getString
(
User
.
USER_NAME
));
}
entry
.
setAuthor
(
authorName
);
final
String
tagsString
=
article
.
getString
(
Article
.
ARTICLE_TAGS_REF
);
final
String
[]
tagStrings
=
tagsString
.
split
(
","
);
for
(
int
j
=
0
;
j
<
tagStrings
.
length
;
j
++)
{
final
Category
catetory
=
new
Category
();
entry
.
addCatetory
(
catetory
);
final
String
tag
=
tagStrings
[
j
];
catetory
.
setTerm
(
tag
);
}
}
renderer
.
setContent
(
feed
.
toString
());
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Get tag article feed error"
,
e
);
try
{
context
.
getResponse
().
sendError
(
HttpServletResponse
.
SC_SERVICE_UNAVAILABLE
);
}
catch
(
final
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
}
/**
* Blog articles RSS output.
*
* @param context the specified context
*/
@RequestProcessing
(
value
=
{
"/blog-articles-rss.do"
},
method
=
{
HTTPRequestMethod
.
GET
,
HTTPRequestMethod
.
HEAD
})
public
void
blogArticlesRSS
(
final
HTTPRequestContext
context
)
{
final
HttpServletResponse
response
=
context
.
getResponse
();
final
RssRenderer
renderer
=
new
RssRenderer
();
context
.
setRenderer
(
renderer
);
final
Channel
channel
=
new
Channel
();
try
{
final
JSONObject
preference
=
preferenceQueryService
.
getPreference
();
if
(
null
==
preference
)
{
response
.
sendError
(
HttpServletResponse
.
SC_NOT_FOUND
);
return
;
}
final
String
blogTitle
=
preference
.
getString
(
Preference
.
BLOG_TITLE
);
final
String
blogSubtitle
=
preference
.
getString
(
Preference
.
BLOG_SUBTITLE
);
final
String
blogHost
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
channel
.
setTitle
(
StringEscapeUtils
.
escapeXml
(
blogTitle
));
channel
.
setLastBuildDate
(
TimeZones
.
getTime
(
preference
.
getString
(
Preference
.
TIME_ZONE_ID
)));
channel
.
setLink
(
"http://"
+
blogHost
);
channel
.
setAtomLink
(
"http://"
+
blogHost
+
"/blog-articles-rss.do"
);
channel
.
setGenerator
(
"B3log Solo, ver "
+
SoloServletListener
.
VERSION
);
final
String
localeString
=
preference
.
getString
(
Preference
.
LOCALE_STRING
);
final
String
country
=
Locales
.
getCountry
(
localeString
).
toLowerCase
();
final
String
language
=
Locales
.
getLanguage
(
localeString
).
toLowerCase
();
channel
.
setLanguage
(
language
+
'-'
+
country
);
channel
.
setDescription
(
blogSubtitle
);
final
Query
query
=
new
Query
().
setCurrentPageNum
(
1
).
setPageSize
(
ENTRY_OUTPUT_CNT
).
setFilter
(
new
PropertyFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
)).
addSort
(
Article
.
ARTICLE_UPDATE_DATE
,
SortDirection
.
DESCENDING
).
setPageCount
(
1
);
final
JSONObject
articleResult
=
articleRepository
.
get
(
query
);
final
JSONArray
articles
=
articleResult
.
getJSONArray
(
Keys
.
RESULTS
);
final
boolean
hasMultipleUsers
=
Users
.
getInstance
().
hasMultipleUsers
();
String
authorName
=
""
;
if
(!
hasMultipleUsers
&&
0
!=
articles
.
length
())
{
authorName
=
articleUtils
.
getAuthor
(
articles
.
getJSONObject
(
0
)).
getString
(
User
.
USER_NAME
);
}
final
boolean
isFullContent
=
"fullContent"
.
equals
(
preference
.
getString
(
Preference
.
FEED_OUTPUT_MODE
));
for
(
int
i
=
0
;
i
<
articles
.
length
();
i
++)
{
final
JSONObject
article
=
articles
.
getJSONObject
(
i
);
final
Item
item
=
new
Item
();
channel
.
addItem
(
item
);
final
String
title
=
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_TITLE
));
item
.
setTitle
(
title
);
final
String
description
=
isFullContent
?
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_CONTENT
))
:
StringEscapeUtils
.
escapeXml
(
article
.
optString
(
Article
.
ARTICLE_ABSTRACT
));
item
.
setDescription
(
description
);
final
Date
pubDate
=
(
Date
)
article
.
get
(
Article
.
ARTICLE_UPDATE_DATE
);
item
.
setPubDate
(
pubDate
);
final
String
link
=
"http://"
+
blogHost
+
article
.
getString
(
Article
.
ARTICLE_PERMALINK
);
item
.
setLink
(
link
);
item
.
setGUID
(
link
);
final
String
authorEmail
=
article
.
getString
(
Article
.
ARTICLE_AUTHOR_EMAIL
);
if
(
hasMultipleUsers
)
{
authorName
=
StringEscapeUtils
.
escapeXml
(
articleUtils
.
getAuthor
(
article
).
getString
(
User
.
USER_NAME
));
}
item
.
setAuthor
(
authorEmail
+
"("
+
authorName
+
")"
);
final
String
tagsString
=
article
.
getString
(
Article
.
ARTICLE_TAGS_REF
);
final
String
[]
tagStrings
=
tagsString
.
split
(
","
);
for
(
int
j
=
0
;
j
<
tagStrings
.
length
;
j
++)
{
final
org
.
b3log
.
solo
.
model
.
feed
.
rss
.
Category
catetory
=
new
org
.
b3log
.
solo
.
model
.
feed
.
rss
.
Category
();
item
.
addCatetory
(
catetory
);
final
String
tag
=
tagStrings
[
j
];
catetory
.
setTerm
(
tag
);
}
}
renderer
.
setContent
(
channel
.
toString
());
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Get blog article rss error"
,
e
);
try
{
context
.
getResponse
().
sendError
(
HttpServletResponse
.
SC_SERVICE_UNAVAILABLE
);
}
catch
(
final
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
}
/**
* Tag articles RSS output.
*
* @param context the specified context
* @throws IOException io exception
*/
@RequestProcessing
(
value
=
{
"/tag-articles-rss.do"
},
method
=
{
HTTPRequestMethod
.
GET
,
HTTPRequestMethod
.
HEAD
})
public
void
tagArticlesRSS
(
final
HTTPRequestContext
context
)
throws
IOException
{
final
HttpServletResponse
response
=
context
.
getResponse
();
final
HttpServletRequest
request
=
context
.
getRequest
();
final
RssRenderer
renderer
=
new
RssRenderer
();
context
.
setRenderer
(
renderer
);
final
String
queryString
=
request
.
getQueryString
();
if
(
Strings
.
isEmptyOrNull
(
queryString
))
{
response
.
sendError
(
HttpServletResponse
.
SC_BAD_REQUEST
);
return
;
}
final
String
oIdMap
=
queryString
.
split
(
"&"
)[
0
];
final
String
tagId
=
oIdMap
.
split
(
"="
)[
1
];
final
Channel
channel
=
new
Channel
();
try
{
final
String
tagTitle
=
tagRepository
.
get
(
tagId
).
getString
(
Tag
.
TAG_TITLE
);
final
JSONObject
preference
=
preferenceQueryService
.
getPreference
();
if
(
null
==
preference
)
{
response
.
sendError
(
HttpServletResponse
.
SC_NOT_FOUND
);
return
;
}
final
String
blogTitle
=
preference
.
getString
(
Preference
.
BLOG_TITLE
);
final
String
blogSubtitle
=
preference
.
getString
(
Preference
.
BLOG_SUBTITLE
)
+
", "
+
tagTitle
;
final
String
blogHost
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
channel
.
setTitle
(
StringEscapeUtils
.
escapeXml
(
blogTitle
));
channel
.
setLastBuildDate
(
TimeZones
.
getTime
(
preference
.
getString
(
Preference
.
TIME_ZONE_ID
)));
channel
.
setLink
(
"http://"
+
blogHost
);
channel
.
setAtomLink
(
"http://"
+
blogHost
+
"/tag-articles-rss.do"
);
channel
.
setGenerator
(
"B3log Solo, ver "
+
SoloServletListener
.
VERSION
);
final
String
localeString
=
preference
.
getString
(
Preference
.
LOCALE_STRING
);
final
String
country
=
Locales
.
getCountry
(
localeString
).
toLowerCase
();
final
String
language
=
Locales
.
getLanguage
(
localeString
).
toLowerCase
();
channel
.
setLanguage
(
language
+
'-'
+
country
);
channel
.
setDescription
(
blogSubtitle
);
final
JSONObject
tagArticleResult
=
tagArticleRepository
.
getByTagId
(
tagId
,
1
,
ENTRY_OUTPUT_CNT
);
final
JSONArray
tagArticleRelations
=
tagArticleResult
.
getJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
tagArticleRelations
.
length
())
{
response
.
sendError
(
HttpServletResponse
.
SC_NOT_FOUND
);
return
;
}
final
List
<
JSONObject
>
articles
=
new
ArrayList
<
JSONObject
>();
for
(
int
i
=
0
;
i
<
tagArticleRelations
.
length
();
i
++)
{
final
JSONObject
tagArticleRelation
=
tagArticleRelations
.
getJSONObject
(
i
);
final
String
articleId
=
tagArticleRelation
.
getString
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
);
final
JSONObject
article
=
articleRepository
.
get
(
articleId
);
if
(
article
.
getBoolean
(
Article
.
ARTICLE_IS_PUBLISHED
))
{
// Skips the unpublished article
articles
.
add
(
article
);
}
}
final
boolean
hasMultipleUsers
=
Users
.
getInstance
().
hasMultipleUsers
();
String
authorName
=
""
;
if
(!
hasMultipleUsers
&&
!
articles
.
isEmpty
())
{
authorName
=
articleUtils
.
getAuthor
(
articles
.
get
(
0
)).
getString
(
User
.
USER_NAME
);
}
final
boolean
isFullContent
=
"fullContent"
.
equals
(
preference
.
getString
(
Preference
.
FEED_OUTPUT_MODE
));
for
(
int
i
=
0
;
i
<
articles
.
size
();
i
++)
{
final
JSONObject
article
=
articles
.
get
(
i
);
final
Item
item
=
new
Item
();
channel
.
addItem
(
item
);
final
String
title
=
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_TITLE
));
item
.
setTitle
(
title
);
final
String
description
=
isFullContent
?
StringEscapeUtils
.
escapeXml
(
article
.
getString
(
Article
.
ARTICLE_CONTENT
))
:
StringEscapeUtils
.
escapeXml
(
article
.
optString
(
Article
.
ARTICLE_ABSTRACT
));
item
.
setDescription
(
description
);
final
Date
pubDate
=
(
Date
)
article
.
get
(
Article
.
ARTICLE_UPDATE_DATE
);
item
.
setPubDate
(
pubDate
);
final
String
link
=
"http://"
+
blogHost
+
article
.
getString
(
Article
.
ARTICLE_PERMALINK
);
item
.
setLink
(
link
);
item
.
setGUID
(
link
);
final
String
authorEmail
=
article
.
getString
(
Article
.
ARTICLE_AUTHOR_EMAIL
);
if
(
hasMultipleUsers
)
{
authorName
=
StringEscapeUtils
.
escapeXml
(
articleUtils
.
getAuthor
(
article
).
getString
(
User
.
USER_NAME
));
}
item
.
setAuthor
(
authorEmail
+
"("
+
authorName
+
")"
);
final
String
tagsString
=
article
.
getString
(
Article
.
ARTICLE_TAGS_REF
);
final
String
[]
tagStrings
=
tagsString
.
split
(
","
);
for
(
int
j
=
0
;
j
<
tagStrings
.
length
;
j
++)
{
final
org
.
b3log
.
solo
.
model
.
feed
.
rss
.
Category
catetory
=
new
org
.
b3log
.
solo
.
model
.
feed
.
rss
.
Category
();
item
.
addCatetory
(
catetory
);
final
String
tag
=
tagStrings
[
j
];
catetory
.
setTerm
(
tag
);
}
}
renderer
.
setContent
(
channel
.
toString
());
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Get tag article rss error"
,
e
);
try
{
context
.
getResponse
().
sendError
(
HttpServletResponse
.
SC_SERVICE_UNAVAILABLE
);
}
catch
(
final
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
}
}
core/src/main/java/org/b3log/solo/processor/SitemapProcessor.java
View file @
4af1a1bb
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
processor
;
import
java.io.IOException
;
import
java.net.URLEncoder
;
import
java.util.Date
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
javax.servlet.http.HttpServletResponse
;
import
org.apache.commons.lang.time.DateFormatUtils
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.annotation.RequestProcessing
;
import
org.b3log.latke.annotation.RequestProcessor
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.Query
;
import
org.b3log.latke.repository.SortDirection
;
import
org.b3log.latke.servlet.HTTPRequestContext
;
import
org.b3log.latke.servlet.HTTPRequestMethod
;
import
org.b3log.latke.servlet.renderer.TextXMLRenderer
;
import
org.b3log.solo.model.ArchiveDate
;
import
org.b3log.solo.model.Article
;
import
org.b3log.solo.model.Page
;
import
org.b3log.solo.model.Preference
;
import
org.b3log.solo.model.Tag
;
import
org.b3log.solo.model.sitemap.Sitemap
;
import
org.b3log.solo.model.sitemap.URL
;
import
org.b3log.solo.repository.ArchiveDateRepository
;
import
org.b3log.solo.repository.PageRepository
;
import
org.b3log.solo.repository.TagRepository
;
import
org.b3log.solo.repository.impl.ArchiveDateRepositoryImpl
;
import
org.b3log.solo.repository.impl.ArticleRepositoryImpl
;
import
org.b3log.solo.repository.impl.PageRepositoryImpl
;
import
org.b3log.solo.repository.impl.TagRepositoryImpl
;
import
org.b3log.solo.service.PreferenceQueryService
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Site map (sitemap) processor.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.4, Jun 11, 2012
* @since 0.3.1
*/
@RequestProcessor
public
final
class
SitemapProcessor
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
SitemapProcessor
.
class
.
getName
());
/**
* Preference query service.
*/
private
PreferenceQueryService
preferenceQueryService
=
PreferenceQueryService
.
getInstance
();
/**
* Article repository.
*/
private
ArticleRepositoryImpl
articleRepository
=
ArticleRepositoryImpl
.
getInstance
();
/**
* Page repository.
*/
private
PageRepository
pageRepository
=
PageRepositoryImpl
.
getInstance
();
/**
* Tag repository.
*/
private
TagRepository
tagRepository
=
TagRepositoryImpl
.
getInstance
();
/**
* Archive date repository.
*/
private
ArchiveDateRepository
archiveDateRepository
=
ArchiveDateRepositoryImpl
.
getInstance
();
/**
* Returns the sitemap.
*
* @param context the specified context
*/
@RequestProcessing
(
value
=
{
"/sitemap.xml"
},
method
=
HTTPRequestMethod
.
GET
)
public
void
sitemap
(
final
HTTPRequestContext
context
)
{
final
TextXMLRenderer
renderer
=
new
TextXMLRenderer
();
context
.
setRenderer
(
renderer
);
final
Sitemap
sitemap
=
new
Sitemap
();
try
{
final
JSONObject
preference
=
preferenceQueryService
.
getPreference
();
addArticles
(
sitemap
,
preference
);
addNavigations
(
sitemap
,
preference
);
addTags
(
sitemap
,
preference
);
addArchives
(
sitemap
,
preference
);
LOGGER
.
log
(
Level
.
INFO
,
"Generating sitemap...."
);
final
String
content
=
sitemap
.
toString
();
LOGGER
.
log
(
Level
.
INFO
,
"Generated sitemap"
);
renderer
.
setContent
(
content
);
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Get blog article feed error"
,
e
);
try
{
context
.
getResponse
().
sendError
(
HttpServletResponse
.
SC_SERVICE_UNAVAILABLE
);
}
catch
(
final
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
}
/**
* Adds articles into the specified sitemap.
*
* @param sitemap the specified sitemap
* @param preference the specified preference
* @throws Exception exception
*/
private
void
addArticles
(
final
Sitemap
sitemap
,
final
JSONObject
preference
)
throws
Exception
{
final
String
host
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
// XXX: query all articles?
final
Query
query
=
new
Query
().
setCurrentPageNum
(
1
).
addFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
).
addSort
(
Article
.
ARTICLE_CREATE_DATE
,
SortDirection
.
DESCENDING
);
// Closes cache avoid Java heap space out of memory while caching
// query results
articleRepository
.
setCacheEnabled
(
false
);
final
JSONObject
articleResult
=
articleRepository
.
get
(
query
);
articleRepository
.
setCacheEnabled
(
true
);
// Restores cache
final
JSONArray
articles
=
articleResult
.
getJSONArray
(
Keys
.
RESULTS
);
for
(
int
i
=
0
;
i
<
articles
.
length
();
i
++)
{
final
JSONObject
article
=
articles
.
getJSONObject
(
i
);
final
String
permalink
=
article
.
getString
(
Article
.
ARTICLE_PERMALINK
);
final
URL
url
=
new
URL
();
url
.
setLoc
(
"http://"
+
host
+
permalink
);
final
Date
updateDate
=
(
Date
)
article
.
get
(
Article
.
ARTICLE_UPDATE_DATE
);
final
String
lastMod
=
DateFormatUtils
.
ISO_DATETIME_TIME_ZONE_FORMAT
.
format
(
updateDate
);
url
.
setLastMod
(
lastMod
);
sitemap
.
addURL
(
url
);
}
}
/**
* Adds navigations into the specified sitemap.
*
* @param sitemap the specified sitemap
* @param preference the specified preference
* @throws Exception exception
*/
private
void
addNavigations
(
final
Sitemap
sitemap
,
final
JSONObject
preference
)
throws
Exception
{
final
String
host
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
final
JSONObject
result
=
pageRepository
.
get
(
new
Query
());
final
JSONArray
pages
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
for
(
int
i
=
0
;
i
<
pages
.
length
();
i
++)
{
final
JSONObject
page
=
pages
.
getJSONObject
(
i
);
final
String
permalink
=
page
.
getString
(
Page
.
PAGE_PERMALINK
);
final
URL
url
=
new
URL
();
// The navigation maybe a page or a link
// Just filters for user mistakes tolerance
if
(!
permalink
.
contains
(
"://"
))
{
url
.
setLoc
(
"http://"
+
host
+
permalink
);
}
else
{
url
.
setLoc
(
permalink
);
}
sitemap
.
addURL
(
url
);
}
}
/**
* Adds tags (tag-articles) and tags wall (/tags.html) into the specified
* sitemap.
*
* @param sitemap the specified sitemap
* @param preference the specified preference
* @throws Exception exception
*/
private
void
addTags
(
final
Sitemap
sitemap
,
final
JSONObject
preference
)
throws
Exception
{
final
String
host
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
final
JSONObject
result
=
tagRepository
.
get
(
new
Query
());
final
JSONArray
tags
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
for
(
int
i
=
0
;
i
<
tags
.
length
();
i
++)
{
final
JSONObject
tag
=
tags
.
getJSONObject
(
i
);
final
String
link
=
URLEncoder
.
encode
(
tag
.
getString
(
Tag
.
TAG_TITLE
),
"UTF-8"
);
final
URL
url
=
new
URL
();
url
.
setLoc
(
"http://"
+
host
+
"/tags/"
+
link
);
sitemap
.
addURL
(
url
);
}
// Tags wall
final
URL
url
=
new
URL
();
url
.
setLoc
(
"http://"
+
host
+
"/tags.html"
);
sitemap
.
addURL
(
url
);
}
/**
* Adds archives (archive-articles) into the specified sitemap.
*
* @param sitemap the specified sitemap
* @param preference the specified preference
* @throws Exception exception
*/
private
void
addArchives
(
final
Sitemap
sitemap
,
final
JSONObject
preference
)
throws
Exception
{
final
String
host
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
final
JSONObject
result
=
archiveDateRepository
.
get
(
new
Query
());
final
JSONArray
archiveDates
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
for
(
int
i
=
0
;
i
<
archiveDates
.
length
();
i
++)
{
final
JSONObject
archiveDate
=
archiveDates
.
getJSONObject
(
i
);
final
long
time
=
archiveDate
.
getLong
(
ArchiveDate
.
ARCHIVE_TIME
);
final
String
dateString
=
ArchiveDate
.
DATE_FORMAT
.
format
(
time
);
final
URL
url
=
new
URL
();
url
.
setLoc
(
"http://"
+
host
+
"/archives/"
+
dateString
);
sitemap
.
addURL
(
url
);
}
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
processor
;
import
java.io.IOException
;
import
java.net.URLEncoder
;
import
java.util.Date
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
javax.servlet.http.HttpServletResponse
;
import
org.apache.commons.lang.time.DateFormatUtils
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.annotation.RequestProcessing
;
import
org.b3log.latke.annotation.RequestProcessor
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.PropertyFilter
;
import
org.b3log.latke.repository.Query
;
import
org.b3log.latke.repository.SortDirection
;
import
org.b3log.latke.servlet.HTTPRequestContext
;
import
org.b3log.latke.servlet.HTTPRequestMethod
;
import
org.b3log.latke.servlet.renderer.TextXMLRenderer
;
import
org.b3log.solo.model.ArchiveDate
;
import
org.b3log.solo.model.Article
;
import
org.b3log.solo.model.Page
;
import
org.b3log.solo.model.Preference
;
import
org.b3log.solo.model.Tag
;
import
org.b3log.solo.model.sitemap.Sitemap
;
import
org.b3log.solo.model.sitemap.URL
;
import
org.b3log.solo.repository.ArchiveDateRepository
;
import
org.b3log.solo.repository.PageRepository
;
import
org.b3log.solo.repository.TagRepository
;
import
org.b3log.solo.repository.impl.ArchiveDateRepositoryImpl
;
import
org.b3log.solo.repository.impl.ArticleRepositoryImpl
;
import
org.b3log.solo.repository.impl.PageRepositoryImpl
;
import
org.b3log.solo.repository.impl.TagRepositoryImpl
;
import
org.b3log.solo.service.PreferenceQueryService
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Site map (sitemap) processor.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.4, Jun 11, 2012
* @since 0.3.1
*/
@RequestProcessor
public
final
class
SitemapProcessor
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
SitemapProcessor
.
class
.
getName
());
/**
* Preference query service.
*/
private
PreferenceQueryService
preferenceQueryService
=
PreferenceQueryService
.
getInstance
();
/**
* Article repository.
*/
private
ArticleRepositoryImpl
articleRepository
=
ArticleRepositoryImpl
.
getInstance
();
/**
* Page repository.
*/
private
PageRepository
pageRepository
=
PageRepositoryImpl
.
getInstance
();
/**
* Tag repository.
*/
private
TagRepository
tagRepository
=
TagRepositoryImpl
.
getInstance
();
/**
* Archive date repository.
*/
private
ArchiveDateRepository
archiveDateRepository
=
ArchiveDateRepositoryImpl
.
getInstance
();
/**
* Returns the sitemap.
*
* @param context the specified context
*/
@RequestProcessing
(
value
=
{
"/sitemap.xml"
},
method
=
HTTPRequestMethod
.
GET
)
public
void
sitemap
(
final
HTTPRequestContext
context
)
{
final
TextXMLRenderer
renderer
=
new
TextXMLRenderer
();
context
.
setRenderer
(
renderer
);
final
Sitemap
sitemap
=
new
Sitemap
();
try
{
final
JSONObject
preference
=
preferenceQueryService
.
getPreference
();
addArticles
(
sitemap
,
preference
);
addNavigations
(
sitemap
,
preference
);
addTags
(
sitemap
,
preference
);
addArchives
(
sitemap
,
preference
);
LOGGER
.
log
(
Level
.
INFO
,
"Generating sitemap...."
);
final
String
content
=
sitemap
.
toString
();
LOGGER
.
log
(
Level
.
INFO
,
"Generated sitemap"
);
renderer
.
setContent
(
content
);
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Get blog article feed error"
,
e
);
try
{
context
.
getResponse
().
sendError
(
HttpServletResponse
.
SC_SERVICE_UNAVAILABLE
);
}
catch
(
final
IOException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
}
/**
* Adds articles into the specified sitemap.
*
* @param sitemap the specified sitemap
* @param preference the specified preference
* @throws Exception exception
*/
private
void
addArticles
(
final
Sitemap
sitemap
,
final
JSONObject
preference
)
throws
Exception
{
final
String
host
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
// XXX: query all articles?
final
Query
query
=
new
Query
().
setCurrentPageNum
(
1
).
setFilter
(
new
PropertyFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
)).
addSort
(
Article
.
ARTICLE_CREATE_DATE
,
SortDirection
.
DESCENDING
);
// Closes cache avoid Java heap space out of memory while caching
// query results
articleRepository
.
setCacheEnabled
(
false
);
final
JSONObject
articleResult
=
articleRepository
.
get
(
query
);
articleRepository
.
setCacheEnabled
(
true
);
// Restores cache
final
JSONArray
articles
=
articleResult
.
getJSONArray
(
Keys
.
RESULTS
);
for
(
int
i
=
0
;
i
<
articles
.
length
();
i
++)
{
final
JSONObject
article
=
articles
.
getJSONObject
(
i
);
final
String
permalink
=
article
.
getString
(
Article
.
ARTICLE_PERMALINK
);
final
URL
url
=
new
URL
();
url
.
setLoc
(
"http://"
+
host
+
permalink
);
final
Date
updateDate
=
(
Date
)
article
.
get
(
Article
.
ARTICLE_UPDATE_DATE
);
final
String
lastMod
=
DateFormatUtils
.
ISO_DATETIME_TIME_ZONE_FORMAT
.
format
(
updateDate
);
url
.
setLastMod
(
lastMod
);
sitemap
.
addURL
(
url
);
}
}
/**
* Adds navigations into the specified sitemap.
*
* @param sitemap the specified sitemap
* @param preference the specified preference
* @throws Exception exception
*/
private
void
addNavigations
(
final
Sitemap
sitemap
,
final
JSONObject
preference
)
throws
Exception
{
final
String
host
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
final
JSONObject
result
=
pageRepository
.
get
(
new
Query
());
final
JSONArray
pages
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
for
(
int
i
=
0
;
i
<
pages
.
length
();
i
++)
{
final
JSONObject
page
=
pages
.
getJSONObject
(
i
);
final
String
permalink
=
page
.
getString
(
Page
.
PAGE_PERMALINK
);
final
URL
url
=
new
URL
();
// The navigation maybe a page or a link
// Just filters for user mistakes tolerance
if
(!
permalink
.
contains
(
"://"
))
{
url
.
setLoc
(
"http://"
+
host
+
permalink
);
}
else
{
url
.
setLoc
(
permalink
);
}
sitemap
.
addURL
(
url
);
}
}
/**
* Adds tags (tag-articles) and tags wall (/tags.html) into the specified
* sitemap.
*
* @param sitemap the specified sitemap
* @param preference the specified preference
* @throws Exception exception
*/
private
void
addTags
(
final
Sitemap
sitemap
,
final
JSONObject
preference
)
throws
Exception
{
final
String
host
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
final
JSONObject
result
=
tagRepository
.
get
(
new
Query
());
final
JSONArray
tags
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
for
(
int
i
=
0
;
i
<
tags
.
length
();
i
++)
{
final
JSONObject
tag
=
tags
.
getJSONObject
(
i
);
final
String
link
=
URLEncoder
.
encode
(
tag
.
getString
(
Tag
.
TAG_TITLE
),
"UTF-8"
);
final
URL
url
=
new
URL
();
url
.
setLoc
(
"http://"
+
host
+
"/tags/"
+
link
);
sitemap
.
addURL
(
url
);
}
// Tags wall
final
URL
url
=
new
URL
();
url
.
setLoc
(
"http://"
+
host
+
"/tags.html"
);
sitemap
.
addURL
(
url
);
}
/**
* Adds archives (archive-articles) into the specified sitemap.
*
* @param sitemap the specified sitemap
* @param preference the specified preference
* @throws Exception exception
*/
private
void
addArchives
(
final
Sitemap
sitemap
,
final
JSONObject
preference
)
throws
Exception
{
final
String
host
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
final
JSONObject
result
=
archiveDateRepository
.
get
(
new
Query
());
final
JSONArray
archiveDates
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
for
(
int
i
=
0
;
i
<
archiveDates
.
length
();
i
++)
{
final
JSONObject
archiveDate
=
archiveDates
.
getJSONObject
(
i
);
final
long
time
=
archiveDate
.
getLong
(
ArchiveDate
.
ARCHIVE_TIME
);
final
String
dateString
=
ArchiveDate
.
DATE_FORMAT
.
format
(
time
);
final
URL
url
=
new
URL
();
url
.
setLoc
(
"http://"
+
host
+
"/archives/"
+
dateString
);
sitemap
.
addURL
(
url
);
}
}
}
core/src/main/java/org/b3log/solo/processor/util/Filler.java
View file @
4af1a1bb
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
processor
.
util
;
import
freemarker.template.Template
;
import
java.util.Calendar
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
javax.servlet.http.HttpServletRequest
;
import
org.apache.commons.lang.StringEscapeUtils
;
import
org.b3log.latke.repository.RepositoryException
;
import
org.b3log.solo.util.Articles
;
import
org.b3log.solo.model.Article
;
import
org.b3log.solo.repository.ArticleRepository
;
import
org.b3log.solo.repository.TagRepository
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.Latkes
;
import
org.b3log.latke.action.AbstractAction
;
import
org.b3log.latke.event.Event
;
import
org.b3log.latke.event.EventException
;
import
org.b3log.latke.event.EventManager
;
import
org.b3log.latke.model.Pagination
;
import
org.b3log.latke.model.Plugin
;
import
org.b3log.latke.model.User
;
import
org.b3log.latke.plugin.ViewLoadEventData
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.Query
;
import
org.b3log.latke.repository.SortDirection
;
import
org.b3log.latke.service.ServiceException
;
import
org.b3log.latke.util.*
;
import
org.b3log.latke.util.freemarker.Templates
;
import
org.b3log.solo.model.ArchiveDate
;
import
org.b3log.solo.model.Link
;
import
org.b3log.solo.model.Preference
;
import
org.b3log.solo.repository.CommentRepository
;
import
org.b3log.solo.repository.LinkRepository
;
import
org.b3log.solo.SoloServletListener
;
import
org.b3log.solo.model.*
;
import
org.b3log.solo.repository.ArchiveDateRepository
;
import
org.b3log.solo.repository.PageRepository
;
import
org.b3log.solo.repository.StatisticRepository
;
import
org.b3log.solo.repository.UserRepository
;
import
org.b3log.solo.repository.impl.ArchiveDateRepositoryImpl
;
import
org.b3log.solo.repository.impl.ArticleRepositoryImpl
;
import
org.b3log.solo.repository.impl.CommentRepositoryImpl
;
import
org.b3log.solo.repository.impl.LinkRepositoryImpl
;
import
org.b3log.solo.repository.impl.PageRepositoryImpl
;
import
org.b3log.solo.repository.impl.StatisticRepositoryImpl
;
import
org.b3log.solo.repository.impl.TagRepositoryImpl
;
import
org.b3log.solo.repository.impl.UserRepositoryImpl
;
import
org.b3log.solo.service.ArticleQueryService
;
import
org.b3log.solo.util.Tags
;
import
org.b3log.solo.util.Users
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
/**
* Filler utilities.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.5.9, May 22, 2012
* @since 0.3.1
*/
public
final
class
Filler
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
Filler
.
class
.
getName
());
/**
* Article repository.
*/
private
ArticleRepository
articleRepository
=
ArticleRepositoryImpl
.
getInstance
();
/**
* Comment repository.
*/
private
CommentRepository
commentRepository
=
CommentRepositoryImpl
.
getInstance
();
/**
* Archive date repository.
*/
private
ArchiveDateRepository
archiveDateRepository
=
ArchiveDateRepositoryImpl
.
getInstance
();
/**
* Tag repository.
*/
private
TagRepository
tagRepository
=
TagRepositoryImpl
.
getInstance
();
/**
* Article utilities.
*/
private
Articles
articleUtils
=
Articles
.
getInstance
();
/**
* Tag utilities.
*/
private
Tags
tagUtils
=
Tags
.
getInstance
();
/**
* Link repository.
*/
private
LinkRepository
linkRepository
=
LinkRepositoryImpl
.
getInstance
();
/**
* Page repository.
*/
private
PageRepository
pageRepository
=
PageRepositoryImpl
.
getInstance
();
/**
* Statistic repository.
*/
private
StatisticRepository
statisticRepository
=
StatisticRepositoryImpl
.
getInstance
();
/**
* User repository.
*/
private
UserRepository
userRepository
=
UserRepositoryImpl
.
getInstance
();
/**
* Article query service.
*/
private
ArticleQueryService
articleQueryService
=
ArticleQueryService
.
getInstance
();
/**
* {@code true} for published.
*/
private
static
final
boolean
PUBLISHED
=
true
;
/**
* Fills articles in index.ftl.
*
* @param dataModel data model
* @param currentPageNum current page number
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillIndexArticles
(
final
Map
<
String
,
Object
>
dataModel
,
final
int
currentPageNum
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Index Articles"
);
try
{
final
int
pageSize
=
preference
.
getInt
(
Preference
.
ARTICLE_LIST_DISPLAY_COUNT
);
final
int
windowSize
=
preference
.
getInt
(
Preference
.
ARTICLE_LIST_PAGINATION_WINDOW_SIZE
);
final
JSONObject
statistic
=
statisticRepository
.
get
(
Statistic
.
STATISTIC
);
final
int
publishedArticleCnt
=
statistic
.
getInt
(
Statistic
.
STATISTIC_PUBLISHED_ARTICLE_COUNT
);
final
int
pageCount
=
(
int
)
Math
.
ceil
((
double
)
publishedArticleCnt
/
(
double
)
pageSize
);
final
Query
query
=
new
Query
().
setCurrentPageNum
(
currentPageNum
).
setPageSize
(
pageSize
).
setPageCount
(
pageCount
).
addFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
PUBLISHED
).
addSort
(
Article
.
ARTICLE_PUT_TOP
,
SortDirection
.
DESCENDING
).
index
(
Article
.
ARTICLE_PERMALINK
);
if
(
preference
.
getBoolean
(
Preference
.
ENABLE_ARTICLE_UPDATE_HINT
))
{
query
.
addSort
(
Article
.
ARTICLE_UPDATE_DATE
,
SortDirection
.
DESCENDING
);
}
else
{
query
.
addSort
(
Article
.
ARTICLE_CREATE_DATE
,
SortDirection
.
DESCENDING
);
}
final
JSONObject
result
=
articleRepository
.
get
(
query
);
final
List
<
Integer
>
pageNums
=
Paginator
.
paginate
(
currentPageNum
,
pageSize
,
pageCount
,
windowSize
);
if
(
0
!=
pageNums
.
size
())
{
dataModel
.
put
(
Pagination
.
PAGINATION_FIRST_PAGE_NUM
,
pageNums
.
get
(
0
));
dataModel
.
put
(
Pagination
.
PAGINATION_LAST_PAGE_NUM
,
pageNums
.
get
(
pageNums
.
size
()
-
1
));
}
dataModel
.
put
(
Pagination
.
PAGINATION_PAGE_COUNT
,
pageCount
);
dataModel
.
put
(
Pagination
.
PAGINATION_PAGE_NUMS
,
pageNums
);
final
List
<
JSONObject
>
articles
=
org
.
b3log
.
latke
.
util
.
CollectionUtils
.
jsonArrayToList
(
result
.
getJSONArray
(
Keys
.
RESULTS
));
final
boolean
hasMultipleUsers
=
Users
.
getInstance
().
hasMultipleUsers
();
if
(
hasMultipleUsers
)
{
setArticlesExProperties
(
articles
,
preference
);
}
else
{
if
(!
articles
.
isEmpty
())
{
final
JSONObject
author
=
articleUtils
.
getAuthor
(
articles
.
get
(
0
));
setArticlesExProperties
(
articles
,
author
,
preference
);
}
}
dataModel
.
put
(
Article
.
ARTICLES
,
articles
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills index articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills index articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills links.
*
* @param dataModel data model
* @throws ServiceException service exception
*/
public
void
fillLinks
(
final
Map
<
String
,
Object
>
dataModel
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Links"
);
try
{
final
Map
<
String
,
SortDirection
>
sorts
=
new
HashMap
<
String
,
SortDirection
>();
sorts
.
put
(
Link
.
LINK_ORDER
,
SortDirection
.
ASCENDING
);
final
Query
query
=
new
Query
().
addSort
(
Link
.
LINK_ORDER
,
SortDirection
.
ASCENDING
).
setPageCount
(
1
);
final
JSONObject
linkResult
=
linkRepository
.
get
(
query
);
final
List
<
JSONObject
>
links
=
org
.
b3log
.
latke
.
util
.
CollectionUtils
.
jsonArrayToList
(
linkResult
.
getJSONArray
(
Keys
.
RESULTS
));
dataModel
.
put
(
Link
.
LINKS
,
links
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills links failed"
,
e
);
throw
new
ServiceException
(
e
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills links failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
Stopwatchs
.
end
();
}
/**
* Fills most used tags.
*
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillMostUsedTags
(
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Most Used Tags"
);
try
{
LOGGER
.
finer
(
"Filling most used tags...."
);
final
int
mostUsedTagDisplayCnt
=
preference
.
getInt
(
Preference
.
MOST_USED_TAG_DISPLAY_CNT
);
final
List
<
JSONObject
>
tags
=
tagRepository
.
getMostUsedTags
(
mostUsedTagDisplayCnt
);
tagUtils
.
removeForUnpublishedArticles
(
tags
);
dataModel
.
put
(
Common
.
MOST_USED_TAGS
,
tags
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills most used tags failed"
,
e
);
throw
new
ServiceException
(
e
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills most used tags failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills archive dates.
*
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillArchiveDates
(
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Archive Dates"
);
try
{
LOGGER
.
finer
(
"Filling archive dates...."
);
final
List
<
JSONObject
>
archiveDates
=
archiveDateRepository
.
getArchiveDates
();
final
String
localeString
=
preference
.
getString
(
Preference
.
LOCALE_STRING
);
final
String
language
=
Locales
.
getLanguage
(
localeString
);
for
(
final
JSONObject
archiveDate
:
archiveDates
)
{
final
long
time
=
archiveDate
.
getLong
(
ArchiveDate
.
ARCHIVE_TIME
);
final
String
dateString
=
ArchiveDate
.
DATE_FORMAT
.
format
(
time
);
final
String
[]
dateStrings
=
dateString
.
split
(
"/"
);
final
String
year
=
dateStrings
[
0
];
final
String
month
=
dateStrings
[
1
];
archiveDate
.
put
(
ArchiveDate
.
ARCHIVE_DATE_YEAR
,
year
);
archiveDate
.
put
(
ArchiveDate
.
ARCHIVE_DATE_MONTH
,
month
);
if
(
"en"
.
equals
(
language
))
{
final
String
monthName
=
Dates
.
EN_MONTHS
.
get
(
month
);
archiveDate
.
put
(
Common
.
MONTH_NAME
,
monthName
);
}
}
dataModel
.
put
(
ArchiveDate
.
ARCHIVE_DATES
,
archiveDates
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills archive dates failed"
,
e
);
throw
new
ServiceException
(
e
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills archive dates failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills most view count articles.
*
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillMostViewCountArticles
(
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Most View Articles"
);
try
{
LOGGER
.
finer
(
"Filling the most view count articles...."
);
final
int
mostCommentArticleDisplayCnt
=
preference
.
getInt
(
Preference
.
MOST_VIEW_ARTICLE_DISPLAY_CNT
);
final
List
<
JSONObject
>
mostViewCountArticles
=
articleRepository
.
getMostViewCountArticles
(
mostCommentArticleDisplayCnt
);
dataModel
.
put
(
Common
.
MOST_VIEW_COUNT_ARTICLES
,
mostViewCountArticles
);
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills most view count articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills most comments articles.
*
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillMostCommentArticles
(
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Most CMMTs Articles"
);
try
{
LOGGER
.
finer
(
"Filling most comment articles...."
);
final
int
mostCommentArticleDisplayCnt
=
preference
.
getInt
(
Preference
.
MOST_COMMENT_ARTICLE_DISPLAY_CNT
);
final
List
<
JSONObject
>
mostCommentArticles
=
articleRepository
.
getMostCommentArticles
(
mostCommentArticleDisplayCnt
);
dataModel
.
put
(
Common
.
MOST_COMMENT_ARTICLES
,
mostCommentArticles
);
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills most comment articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills post articles recently.
*
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillRecentArticles
(
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Recent Articles"
);
try
{
final
int
recentArticleDisplayCnt
=
preference
.
getInt
(
Preference
.
RECENT_ARTICLE_DISPLAY_CNT
);
final
List
<
JSONObject
>
recentArticles
=
articleRepository
.
getRecentArticles
(
recentArticleDisplayCnt
);
dataModel
.
put
(
Common
.
RECENT_ARTICLES
,
recentArticles
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills recent articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills recent articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills post comments recently.
*
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillRecentComments
(
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Recent Comments"
);
try
{
LOGGER
.
finer
(
"Filling recent comments...."
);
final
int
recentCommentDisplayCnt
=
preference
.
getInt
(
Preference
.
RECENT_COMMENT_DISPLAY_CNT
);
final
List
<
JSONObject
>
recentComments
=
commentRepository
.
getRecentComments
(
recentCommentDisplayCnt
);
for
(
final
JSONObject
comment
:
recentComments
)
{
final
String
content
=
comment
.
getString
(
Comment
.
COMMENT_CONTENT
).
replaceAll
(
SoloServletListener
.
ENTER_ESC
,
" "
);
comment
.
put
(
Comment
.
COMMENT_CONTENT
,
content
);
comment
.
put
(
Comment
.
COMMENT_NAME
,
StringEscapeUtils
.
escapeHtml
(
comment
.
getString
(
Comment
.
COMMENT_NAME
)));
comment
.
put
(
Comment
.
COMMENT_URL
,
StringEscapeUtils
.
escapeHtml
(
comment
.
getString
(
Comment
.
COMMENT_URL
)));
comment
.
remove
(
Comment
.
COMMENT_EMAIL
);
// Erases email for security reason
}
dataModel
.
put
(
Common
.
RECENT_COMMENTS
,
recentComments
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills recent comments failed"
,
e
);
throw
new
ServiceException
(
e
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills recent comments failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills footer.ftl.
*
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillBlogFooter
(
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Footer"
);
try
{
LOGGER
.
finer
(
"Filling footer...."
);
final
String
blogTitle
=
preference
.
getString
(
Preference
.
BLOG_TITLE
);
dataModel
.
put
(
Preference
.
BLOG_TITLE
,
blogTitle
);
final
String
blogHost
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
dataModel
.
put
(
Preference
.
BLOG_HOST
,
blogHost
);
dataModel
.
put
(
Common
.
VERSION
,
SoloServletListener
.
VERSION
);
dataModel
.
put
(
Common
.
STATIC_RESOURCE_VERSION
,
Latkes
.
getStaticResourceVersion
());
dataModel
.
put
(
Common
.
YEAR
,
String
.
valueOf
(
Calendar
.
getInstance
().
get
(
Calendar
.
YEAR
)));
dataModel
.
put
(
Keys
.
Server
.
STATIC_SERVER
,
Latkes
.
getStaticServer
());
dataModel
.
put
(
Keys
.
Server
.
SERVER
,
Latkes
.
getServer
());
// Activates plugins
try
{
final
ViewLoadEventData
data
=
new
ViewLoadEventData
();
data
.
setViewName
(
"footer.ftl"
);
data
.
setDataModel
(
dataModel
);
EventManager
.
getInstance
().
fireEventSynchronously
(
new
Event
<
ViewLoadEventData
>(
AbstractAction
.
FREEMARKER_ACTION
,
data
));
if
(
Strings
.
isEmptyOrNull
((
String
)
dataModel
.
get
(
Plugin
.
PLUGINS
)))
{
// There is no plugin for this template, fill ${plugins} with blank.
dataModel
.
put
(
Plugin
.
PLUGINS
,
""
);
}
}
catch
(
final
EventException
e
)
{
LOGGER
.
log
(
Level
.
WARNING
,
"Event[FREEMARKER_ACTION] handle failed, ignores this exception for kernel health"
,
e
);
}
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills blog footer failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills header.ftl.
*
* @param request the specified HTTP servlet request
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillBlogHeader
(
final
HttpServletRequest
request
,
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Header"
);
try
{
LOGGER
.
fine
(
"Filling header...."
);
dataModel
.
put
(
Preference
.
ARTICLE_LIST_DISPLAY_COUNT
,
preference
.
getInt
(
Preference
.
ARTICLE_LIST_DISPLAY_COUNT
));
dataModel
.
put
(
Preference
.
ARTICLE_LIST_PAGINATION_WINDOW_SIZE
,
preference
.
getInt
(
Preference
.
ARTICLE_LIST_PAGINATION_WINDOW_SIZE
));
dataModel
.
put
(
Preference
.
LOCALE_STRING
,
preference
.
getString
(
Preference
.
LOCALE_STRING
));
dataModel
.
put
(
Preference
.
BLOG_TITLE
,
preference
.
getString
(
Preference
.
BLOG_TITLE
));
dataModel
.
put
(
Preference
.
BLOG_SUBTITLE
,
preference
.
getString
(
Preference
.
BLOG_SUBTITLE
));
dataModel
.
put
(
Preference
.
HTML_HEAD
,
preference
.
getString
(
Preference
.
HTML_HEAD
));
dataModel
.
put
(
Preference
.
META_KEYWORDS
,
preference
.
getString
(
Preference
.
META_KEYWORDS
));
dataModel
.
put
(
Preference
.
META_DESCRIPTION
,
preference
.
getString
(
Preference
.
META_DESCRIPTION
));
dataModel
.
put
(
Common
.
YEAR
,
String
.
valueOf
(
Calendar
.
getInstance
().
get
(
Calendar
.
YEAR
)));
final
String
noticeBoard
=
preference
.
getString
(
Preference
.
NOTICE_BOARD
);
dataModel
.
put
(
Preference
.
NOTICE_BOARD
,
noticeBoard
);
final
Query
query
=
new
Query
().
setPageCount
(
1
);
final
JSONObject
result
=
userRepository
.
get
(
query
);
final
JSONArray
users
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
final
List
<
JSONObject
>
userList
=
CollectionUtils
.
jsonArrayToList
(
users
);
dataModel
.
put
(
User
.
USERS
,
userList
);
for
(
final
JSONObject
user
:
userList
)
{
user
.
remove
(
User
.
USER_EMAIL
);
}
final
String
skinDirName
=
(
String
)
request
.
getAttribute
(
Keys
.
TEMAPLTE_DIR_NAME
);
dataModel
.
put
(
Skin
.
SKIN_DIR_NAME
,
skinDirName
);
Keys
.
fillServer
(
dataModel
);
fillMinified
(
dataModel
);
fillPageNavigations
(
dataModel
);
fillStatistic
(
dataModel
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills blog header failed"
,
e
);
throw
new
ServiceException
(
e
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills blog header failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills minified directory and file postfix for static JavaScript, CSS.
*
* @param dataModel the specified data model
*/
public
void
fillMinified
(
final
Map
<
String
,
Object
>
dataModel
)
{
switch
(
Latkes
.
getRuntimeMode
())
{
case
DEVELOPMENT:
dataModel
.
put
(
Common
.
MINI_POSTFIX
,
""
);
break
;
case
PRODUCTION:
dataModel
.
put
(
Common
.
MINI_POSTFIX
,
Common
.
MINI_POSTFIX_VALUE
);
break
;
default
:
throw
new
AssertionError
();
}
}
/**
* Fills side.ftl.
*
* @param request the specified HTTP servlet request
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillSide
(
final
HttpServletRequest
request
,
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Side"
);
try
{
LOGGER
.
fine
(
"Filling side...."
);
final
Template
template
=
Templates
.
getTemplate
((
String
)
request
.
getAttribute
(
Keys
.
TEMAPLTE_DIR_NAME
),
"side.ftl"
);
if
(
null
==
template
)
{
LOGGER
.
fine
(
"The skin dose not contain [side.ftl] template"
);
return
;
}
// TODO: fillRecentArticles(dataModel, preference);
if
(
Templates
.
hasExpression
(
template
,
"<#list links as link>"
))
{
fillLinks
(
dataModel
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list recentComments as comment>"
))
{
fillRecentComments
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list mostUsedTags as tag>"
))
{
fillMostUsedTags
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list mostCommentArticles as article>"
))
{
fillMostCommentArticles
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list mostViewCountArticles as article>"
))
{
fillMostViewCountArticles
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list archiveDates as archiveDate>"
))
{
fillArchiveDates
(
dataModel
,
preference
);
}
}
catch
(
final
ServiceException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills side failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills the specified template.
*
* @param template the specified template
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillUserTemplate
(
final
Template
template
,
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill User Template[name="
+
template
.
getName
()
+
"]"
);
try
{
LOGGER
.
log
(
Level
.
FINE
,
"Filling user template[name{0}]"
,
template
.
getName
());
if
(
Templates
.
hasExpression
(
template
,
"<#list links as link>"
))
{
fillLinks
(
dataModel
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list recentComments as comment>"
))
{
fillRecentComments
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list mostUsedTags as tag>"
))
{
fillMostUsedTags
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list mostCommentArticles as article>"
))
{
fillMostCommentArticles
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list mostViewCountArticles as article>"
))
{
fillMostViewCountArticles
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list archiveDates as archiveDate>"
))
{
fillArchiveDates
(
dataModel
,
preference
);
}
final
String
noticeBoard
=
preference
.
getString
(
Preference
.
NOTICE_BOARD
);
dataModel
.
put
(
Preference
.
NOTICE_BOARD
,
noticeBoard
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills user template failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills page navigations.
*
* @param dataModel data model
* @throws ServiceException service exception
*/
private
void
fillPageNavigations
(
final
Map
<
String
,
Object
>
dataModel
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Navigations"
);
try
{
LOGGER
.
finer
(
"Filling page navigations...."
);
final
List
<
JSONObject
>
pages
=
pageRepository
.
getPages
();
for
(
final
JSONObject
page
:
pages
)
{
if
(
"page"
.
equals
(
page
.
optString
(
Page
.
PAGE_TYPE
)))
{
final
String
permalink
=
page
.
optString
(
Page
.
PAGE_PERMALINK
);
page
.
put
(
Page
.
PAGE_PERMALINK
,
Latkes
.
getServePath
()
+
permalink
);
}
}
dataModel
.
put
(
Common
.
PAGE_NAVIGATIONS
,
pages
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills page navigations failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills statistic.
*
* @param dataModel data model
* @throws ServiceException service exception
*/
private
void
fillStatistic
(
final
Map
<
String
,
Object
>
dataModel
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Statistic"
);
try
{
LOGGER
.
finer
(
"Filling statistic...."
);
final
JSONObject
statistic
=
statisticRepository
.
get
(
Statistic
.
STATISTIC
);
dataModel
.
put
(
Statistic
.
STATISTIC
,
statistic
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills statistic failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Sets some extra properties into the specified article with the specified author and preference, performs content and
* abstract editor processing.
*
* <p>
* Article ext properties:
* <pre>
* {
* ....,
* "authorName": "",
* "authorId": "",
* "hasUpdated": boolean
* }
* </pre>
* </p>
*
* @param article the specified article
* @param author the specified author
* @param preference the specified preference
* @throws ServiceException service exception
* @see #setArticlesExProperties(java.util.List, org.json.JSONObject)
*/
private
void
setArticleExProperties
(
final
JSONObject
article
,
final
JSONObject
author
,
final
JSONObject
preference
)
throws
ServiceException
{
try
{
final
String
authorName
=
author
.
getString
(
User
.
USER_NAME
);
article
.
put
(
Common
.
AUTHOR_NAME
,
authorName
);
final
String
authorId
=
author
.
getString
(
Keys
.
OBJECT_ID
);
article
.
put
(
Common
.
AUTHOR_ID
,
authorId
);
if
(
preference
.
getBoolean
(
Preference
.
ENABLE_ARTICLE_UPDATE_HINT
))
{
article
.
put
(
Common
.
HAS_UPDATED
,
articleUtils
.
hasUpdated
(
article
));
}
else
{
article
.
put
(
Common
.
HAS_UPDATED
,
false
);
}
processArticleAbstract
(
preference
,
article
);
articleQueryService
.
markdown
(
article
);
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Sets article extra properties failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Sets some extra properties into the specified article with the specified preference, performs content and
* abstract editor processing.
*
* <p>
* Article ext properties:
* <pre>
* {
* ....,
* "authorName": "",
* "authorId": "",
* "hasUpdated": boolean
* }
* </pre>
* </p>
*
* @param article the specified article
* @param preference the specified preference
* @throws ServiceException service exception
* @see #setArticlesExProperties(java.util.List, org.json.JSONObject)
*/
private
void
setArticleExProperties
(
final
JSONObject
article
,
final
JSONObject
preference
)
throws
ServiceException
{
try
{
final
JSONObject
author
=
articleUtils
.
getAuthor
(
article
);
final
String
authorName
=
author
.
getString
(
User
.
USER_NAME
);
article
.
put
(
Common
.
AUTHOR_NAME
,
authorName
);
final
String
authorId
=
author
.
getString
(
Keys
.
OBJECT_ID
);
article
.
put
(
Common
.
AUTHOR_ID
,
authorId
);
if
(
preference
.
getBoolean
(
Preference
.
ENABLE_ARTICLE_UPDATE_HINT
))
{
article
.
put
(
Common
.
HAS_UPDATED
,
articleUtils
.
hasUpdated
(
article
));
}
else
{
article
.
put
(
Common
.
HAS_UPDATED
,
false
);
}
processArticleAbstract
(
preference
,
article
);
articleQueryService
.
markdown
(
article
);
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Sets article extra properties failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Sets some extra properties into the specified article with the specified
* author and preference.
*
* <p>
* The batch version of method
* {@linkplain #setArticleExProperties(org.json.JSONObject, org.json.JSONObject)}.
* </p>
*
* <p>
* Article ext properties:
* <pre>
* {
* ....,
* "authorName": "",
* "authorId": "",
* "hasUpdated": boolean
* }
* </pre>
* </p>
*
* @param articles the specified articles
* @param author the specified author
* @param preference the specified preference
* @throws ServiceException service exception
* @see #setArticleExProperties(org.json.JSONObject, org.json.JSONObject)
*/
public
void
setArticlesExProperties
(
final
List
<
JSONObject
>
articles
,
final
JSONObject
author
,
final
JSONObject
preference
)
throws
ServiceException
{
for
(
final
JSONObject
article
:
articles
)
{
setArticleExProperties
(
article
,
author
,
preference
);
}
}
/**
* Sets some extra properties into the specified article with the specified
* preference.
*
* <p>
* The batch version of method
* {@linkplain #setArticleExProperties(org.json.JSONObject, org.json.JSONObject)}.
* </p>
*
* <p>
* Article ext properties:
* <pre>
* {
* ....,
* "authorName": "",
* "authorId": "",
* "hasUpdated": boolean
* }
* </pre>
* </p>
*
* @param articles the specified articles
* @param preference the specified preference
* @throws ServiceException service exception
* @see #setArticleExProperties(org.json.JSONObject, org.json.JSONObject)
*/
public
void
setArticlesExProperties
(
final
List
<
JSONObject
>
articles
,
final
JSONObject
preference
)
throws
ServiceException
{
for
(
final
JSONObject
article
:
articles
)
{
setArticleExProperties
(
article
,
preference
);
}
}
/**
* Processes the abstract of the specified article with the specified preference.
*
* <p>
* <ul>
* <li>If the abstract is {@code null}, sets it with ""</li>
* <li>If user configured preference "titleOnly", sets the abstract with ""</li>
* <li>If user configured preference "titleAndContent", sets the abstract with the content of the article</li>
* </ul>
* </p>
*
* @param preference the specified preference
* @param article the specified article
*/
private
void
processArticleAbstract
(
final
JSONObject
preference
,
final
JSONObject
article
)
{
final
String
articleAbstract
=
article
.
optString
(
Article
.
ARTICLE_ABSTRACT
,
null
);
if
(
null
==
articleAbstract
)
{
article
.
put
(
Article
.
ARTICLE_ABSTRACT
,
""
);
}
final
String
articleListStyle
=
preference
.
optString
(
Preference
.
ARTICLE_LIST_STYLE
);
if
(
"titleOnly"
.
equals
(
articleListStyle
))
{
article
.
put
(
Article
.
ARTICLE_ABSTRACT
,
""
);
}
else
if
(
"titleAndContent"
.
equals
(
articleListStyle
))
{
article
.
put
(
Article
.
ARTICLE_ABSTRACT
,
article
.
optString
(
Article
.
ARTICLE_CONTENT
));
}
}
/**
* Gets the {@link Filler} singleton.
*
* @return the singleton
*/
public
static
Filler
getInstance
()
{
return
SingletonHolder
.
SINGLETON
;
}
/**
* Private default constructor.
*/
private
Filler
()
{
}
/**
* Singleton holder.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Jan 12, 2011
*/
private
static
final
class
SingletonHolder
{
/**
* Singleton.
*/
private
static
final
Filler
SINGLETON
=
new
Filler
();
/**
* Private default constructor.
*/
private
SingletonHolder
()
{
}
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
processor
.
util
;
import
freemarker.template.Template
;
import
java.util.Calendar
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
javax.servlet.http.HttpServletRequest
;
import
org.apache.commons.lang.StringEscapeUtils
;
import
org.b3log.latke.repository.RepositoryException
;
import
org.b3log.solo.util.Articles
;
import
org.b3log.solo.model.Article
;
import
org.b3log.solo.repository.ArticleRepository
;
import
org.b3log.solo.repository.TagRepository
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.Latkes
;
import
org.b3log.latke.action.AbstractAction
;
import
org.b3log.latke.event.Event
;
import
org.b3log.latke.event.EventException
;
import
org.b3log.latke.event.EventManager
;
import
org.b3log.latke.model.Pagination
;
import
org.b3log.latke.model.Plugin
;
import
org.b3log.latke.model.User
;
import
org.b3log.latke.plugin.ViewLoadEventData
;
import
org.b3log.latke.repository.*
;
import
org.b3log.latke.service.ServiceException
;
import
org.b3log.latke.util.*
;
import
org.b3log.latke.util.freemarker.Templates
;
import
org.b3log.solo.model.ArchiveDate
;
import
org.b3log.solo.model.Link
;
import
org.b3log.solo.model.Preference
;
import
org.b3log.solo.repository.CommentRepository
;
import
org.b3log.solo.repository.LinkRepository
;
import
org.b3log.solo.SoloServletListener
;
import
org.b3log.solo.model.*
;
import
org.b3log.solo.repository.ArchiveDateRepository
;
import
org.b3log.solo.repository.PageRepository
;
import
org.b3log.solo.repository.StatisticRepository
;
import
org.b3log.solo.repository.UserRepository
;
import
org.b3log.solo.repository.impl.ArchiveDateRepositoryImpl
;
import
org.b3log.solo.repository.impl.ArticleRepositoryImpl
;
import
org.b3log.solo.repository.impl.CommentRepositoryImpl
;
import
org.b3log.solo.repository.impl.LinkRepositoryImpl
;
import
org.b3log.solo.repository.impl.PageRepositoryImpl
;
import
org.b3log.solo.repository.impl.StatisticRepositoryImpl
;
import
org.b3log.solo.repository.impl.TagRepositoryImpl
;
import
org.b3log.solo.repository.impl.UserRepositoryImpl
;
import
org.b3log.solo.service.ArticleQueryService
;
import
org.b3log.solo.util.Tags
;
import
org.b3log.solo.util.Users
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
/**
* Filler utilities.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.5.9, May 22, 2012
* @since 0.3.1
*/
public
final
class
Filler
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
Filler
.
class
.
getName
());
/**
* Article repository.
*/
private
ArticleRepository
articleRepository
=
ArticleRepositoryImpl
.
getInstance
();
/**
* Comment repository.
*/
private
CommentRepository
commentRepository
=
CommentRepositoryImpl
.
getInstance
();
/**
* Archive date repository.
*/
private
ArchiveDateRepository
archiveDateRepository
=
ArchiveDateRepositoryImpl
.
getInstance
();
/**
* Tag repository.
*/
private
TagRepository
tagRepository
=
TagRepositoryImpl
.
getInstance
();
/**
* Article utilities.
*/
private
Articles
articleUtils
=
Articles
.
getInstance
();
/**
* Tag utilities.
*/
private
Tags
tagUtils
=
Tags
.
getInstance
();
/**
* Link repository.
*/
private
LinkRepository
linkRepository
=
LinkRepositoryImpl
.
getInstance
();
/**
* Page repository.
*/
private
PageRepository
pageRepository
=
PageRepositoryImpl
.
getInstance
();
/**
* Statistic repository.
*/
private
StatisticRepository
statisticRepository
=
StatisticRepositoryImpl
.
getInstance
();
/**
* User repository.
*/
private
UserRepository
userRepository
=
UserRepositoryImpl
.
getInstance
();
/**
* Article query service.
*/
private
ArticleQueryService
articleQueryService
=
ArticleQueryService
.
getInstance
();
/**
* {@code true} for published.
*/
private
static
final
boolean
PUBLISHED
=
true
;
/**
* Fills articles in index.ftl.
*
* @param dataModel data model
* @param currentPageNum current page number
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillIndexArticles
(
final
Map
<
String
,
Object
>
dataModel
,
final
int
currentPageNum
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Index Articles"
);
try
{
final
int
pageSize
=
preference
.
getInt
(
Preference
.
ARTICLE_LIST_DISPLAY_COUNT
);
final
int
windowSize
=
preference
.
getInt
(
Preference
.
ARTICLE_LIST_PAGINATION_WINDOW_SIZE
);
final
JSONObject
statistic
=
statisticRepository
.
get
(
Statistic
.
STATISTIC
);
final
int
publishedArticleCnt
=
statistic
.
getInt
(
Statistic
.
STATISTIC_PUBLISHED_ARTICLE_COUNT
);
final
int
pageCount
=
(
int
)
Math
.
ceil
((
double
)
publishedArticleCnt
/
(
double
)
pageSize
);
final
Query
query
=
new
Query
().
setCurrentPageNum
(
currentPageNum
).
setPageSize
(
pageSize
).
setPageCount
(
pageCount
).
setFilter
(
new
PropertyFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
PUBLISHED
)).
addSort
(
Article
.
ARTICLE_PUT_TOP
,
SortDirection
.
DESCENDING
).
index
(
Article
.
ARTICLE_PERMALINK
);
if
(
preference
.
getBoolean
(
Preference
.
ENABLE_ARTICLE_UPDATE_HINT
))
{
query
.
addSort
(
Article
.
ARTICLE_UPDATE_DATE
,
SortDirection
.
DESCENDING
);
}
else
{
query
.
addSort
(
Article
.
ARTICLE_CREATE_DATE
,
SortDirection
.
DESCENDING
);
}
final
JSONObject
result
=
articleRepository
.
get
(
query
);
final
List
<
Integer
>
pageNums
=
Paginator
.
paginate
(
currentPageNum
,
pageSize
,
pageCount
,
windowSize
);
if
(
0
!=
pageNums
.
size
())
{
dataModel
.
put
(
Pagination
.
PAGINATION_FIRST_PAGE_NUM
,
pageNums
.
get
(
0
));
dataModel
.
put
(
Pagination
.
PAGINATION_LAST_PAGE_NUM
,
pageNums
.
get
(
pageNums
.
size
()
-
1
));
}
dataModel
.
put
(
Pagination
.
PAGINATION_PAGE_COUNT
,
pageCount
);
dataModel
.
put
(
Pagination
.
PAGINATION_PAGE_NUMS
,
pageNums
);
final
List
<
JSONObject
>
articles
=
org
.
b3log
.
latke
.
util
.
CollectionUtils
.
jsonArrayToList
(
result
.
getJSONArray
(
Keys
.
RESULTS
));
final
boolean
hasMultipleUsers
=
Users
.
getInstance
().
hasMultipleUsers
();
if
(
hasMultipleUsers
)
{
setArticlesExProperties
(
articles
,
preference
);
}
else
{
if
(!
articles
.
isEmpty
())
{
final
JSONObject
author
=
articleUtils
.
getAuthor
(
articles
.
get
(
0
));
setArticlesExProperties
(
articles
,
author
,
preference
);
}
}
dataModel
.
put
(
Article
.
ARTICLES
,
articles
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills index articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills index articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills links.
*
* @param dataModel data model
* @throws ServiceException service exception
*/
public
void
fillLinks
(
final
Map
<
String
,
Object
>
dataModel
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Links"
);
try
{
final
Map
<
String
,
SortDirection
>
sorts
=
new
HashMap
<
String
,
SortDirection
>();
sorts
.
put
(
Link
.
LINK_ORDER
,
SortDirection
.
ASCENDING
);
final
Query
query
=
new
Query
().
addSort
(
Link
.
LINK_ORDER
,
SortDirection
.
ASCENDING
).
setPageCount
(
1
);
final
JSONObject
linkResult
=
linkRepository
.
get
(
query
);
final
List
<
JSONObject
>
links
=
org
.
b3log
.
latke
.
util
.
CollectionUtils
.
jsonArrayToList
(
linkResult
.
getJSONArray
(
Keys
.
RESULTS
));
dataModel
.
put
(
Link
.
LINKS
,
links
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills links failed"
,
e
);
throw
new
ServiceException
(
e
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills links failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
Stopwatchs
.
end
();
}
/**
* Fills most used tags.
*
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillMostUsedTags
(
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Most Used Tags"
);
try
{
LOGGER
.
finer
(
"Filling most used tags...."
);
final
int
mostUsedTagDisplayCnt
=
preference
.
getInt
(
Preference
.
MOST_USED_TAG_DISPLAY_CNT
);
final
List
<
JSONObject
>
tags
=
tagRepository
.
getMostUsedTags
(
mostUsedTagDisplayCnt
);
tagUtils
.
removeForUnpublishedArticles
(
tags
);
dataModel
.
put
(
Common
.
MOST_USED_TAGS
,
tags
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills most used tags failed"
,
e
);
throw
new
ServiceException
(
e
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills most used tags failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills archive dates.
*
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillArchiveDates
(
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Archive Dates"
);
try
{
LOGGER
.
finer
(
"Filling archive dates...."
);
final
List
<
JSONObject
>
archiveDates
=
archiveDateRepository
.
getArchiveDates
();
final
String
localeString
=
preference
.
getString
(
Preference
.
LOCALE_STRING
);
final
String
language
=
Locales
.
getLanguage
(
localeString
);
for
(
final
JSONObject
archiveDate
:
archiveDates
)
{
final
long
time
=
archiveDate
.
getLong
(
ArchiveDate
.
ARCHIVE_TIME
);
final
String
dateString
=
ArchiveDate
.
DATE_FORMAT
.
format
(
time
);
final
String
[]
dateStrings
=
dateString
.
split
(
"/"
);
final
String
year
=
dateStrings
[
0
];
final
String
month
=
dateStrings
[
1
];
archiveDate
.
put
(
ArchiveDate
.
ARCHIVE_DATE_YEAR
,
year
);
archiveDate
.
put
(
ArchiveDate
.
ARCHIVE_DATE_MONTH
,
month
);
if
(
"en"
.
equals
(
language
))
{
final
String
monthName
=
Dates
.
EN_MONTHS
.
get
(
month
);
archiveDate
.
put
(
Common
.
MONTH_NAME
,
monthName
);
}
}
dataModel
.
put
(
ArchiveDate
.
ARCHIVE_DATES
,
archiveDates
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills archive dates failed"
,
e
);
throw
new
ServiceException
(
e
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills archive dates failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills most view count articles.
*
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillMostViewCountArticles
(
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Most View Articles"
);
try
{
LOGGER
.
finer
(
"Filling the most view count articles...."
);
final
int
mostCommentArticleDisplayCnt
=
preference
.
getInt
(
Preference
.
MOST_VIEW_ARTICLE_DISPLAY_CNT
);
final
List
<
JSONObject
>
mostViewCountArticles
=
articleRepository
.
getMostViewCountArticles
(
mostCommentArticleDisplayCnt
);
dataModel
.
put
(
Common
.
MOST_VIEW_COUNT_ARTICLES
,
mostViewCountArticles
);
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills most view count articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills most comments articles.
*
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillMostCommentArticles
(
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Most CMMTs Articles"
);
try
{
LOGGER
.
finer
(
"Filling most comment articles...."
);
final
int
mostCommentArticleDisplayCnt
=
preference
.
getInt
(
Preference
.
MOST_COMMENT_ARTICLE_DISPLAY_CNT
);
final
List
<
JSONObject
>
mostCommentArticles
=
articleRepository
.
getMostCommentArticles
(
mostCommentArticleDisplayCnt
);
dataModel
.
put
(
Common
.
MOST_COMMENT_ARTICLES
,
mostCommentArticles
);
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills most comment articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills post articles recently.
*
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillRecentArticles
(
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Recent Articles"
);
try
{
final
int
recentArticleDisplayCnt
=
preference
.
getInt
(
Preference
.
RECENT_ARTICLE_DISPLAY_CNT
);
final
List
<
JSONObject
>
recentArticles
=
articleRepository
.
getRecentArticles
(
recentArticleDisplayCnt
);
dataModel
.
put
(
Common
.
RECENT_ARTICLES
,
recentArticles
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills recent articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills recent articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills post comments recently.
*
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillRecentComments
(
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Recent Comments"
);
try
{
LOGGER
.
finer
(
"Filling recent comments...."
);
final
int
recentCommentDisplayCnt
=
preference
.
getInt
(
Preference
.
RECENT_COMMENT_DISPLAY_CNT
);
final
List
<
JSONObject
>
recentComments
=
commentRepository
.
getRecentComments
(
recentCommentDisplayCnt
);
for
(
final
JSONObject
comment
:
recentComments
)
{
final
String
content
=
comment
.
getString
(
Comment
.
COMMENT_CONTENT
).
replaceAll
(
SoloServletListener
.
ENTER_ESC
,
" "
);
comment
.
put
(
Comment
.
COMMENT_CONTENT
,
content
);
comment
.
put
(
Comment
.
COMMENT_NAME
,
StringEscapeUtils
.
escapeHtml
(
comment
.
getString
(
Comment
.
COMMENT_NAME
)));
comment
.
put
(
Comment
.
COMMENT_URL
,
StringEscapeUtils
.
escapeHtml
(
comment
.
getString
(
Comment
.
COMMENT_URL
)));
comment
.
remove
(
Comment
.
COMMENT_EMAIL
);
// Erases email for security reason
}
dataModel
.
put
(
Common
.
RECENT_COMMENTS
,
recentComments
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills recent comments failed"
,
e
);
throw
new
ServiceException
(
e
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills recent comments failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills footer.ftl.
*
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillBlogFooter
(
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Footer"
);
try
{
LOGGER
.
finer
(
"Filling footer...."
);
final
String
blogTitle
=
preference
.
getString
(
Preference
.
BLOG_TITLE
);
dataModel
.
put
(
Preference
.
BLOG_TITLE
,
blogTitle
);
final
String
blogHost
=
preference
.
getString
(
Preference
.
BLOG_HOST
);
dataModel
.
put
(
Preference
.
BLOG_HOST
,
blogHost
);
dataModel
.
put
(
Common
.
VERSION
,
SoloServletListener
.
VERSION
);
dataModel
.
put
(
Common
.
STATIC_RESOURCE_VERSION
,
Latkes
.
getStaticResourceVersion
());
dataModel
.
put
(
Common
.
YEAR
,
String
.
valueOf
(
Calendar
.
getInstance
().
get
(
Calendar
.
YEAR
)));
dataModel
.
put
(
Keys
.
Server
.
STATIC_SERVER
,
Latkes
.
getStaticServer
());
dataModel
.
put
(
Keys
.
Server
.
SERVER
,
Latkes
.
getServer
());
// Activates plugins
try
{
final
ViewLoadEventData
data
=
new
ViewLoadEventData
();
data
.
setViewName
(
"footer.ftl"
);
data
.
setDataModel
(
dataModel
);
EventManager
.
getInstance
().
fireEventSynchronously
(
new
Event
<
ViewLoadEventData
>(
AbstractAction
.
FREEMARKER_ACTION
,
data
));
if
(
Strings
.
isEmptyOrNull
((
String
)
dataModel
.
get
(
Plugin
.
PLUGINS
)))
{
// There is no plugin for this template, fill ${plugins} with blank.
dataModel
.
put
(
Plugin
.
PLUGINS
,
""
);
}
}
catch
(
final
EventException
e
)
{
LOGGER
.
log
(
Level
.
WARNING
,
"Event[FREEMARKER_ACTION] handle failed, ignores this exception for kernel health"
,
e
);
}
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills blog footer failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills header.ftl.
*
* @param request the specified HTTP servlet request
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillBlogHeader
(
final
HttpServletRequest
request
,
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Header"
);
try
{
LOGGER
.
fine
(
"Filling header...."
);
dataModel
.
put
(
Preference
.
ARTICLE_LIST_DISPLAY_COUNT
,
preference
.
getInt
(
Preference
.
ARTICLE_LIST_DISPLAY_COUNT
));
dataModel
.
put
(
Preference
.
ARTICLE_LIST_PAGINATION_WINDOW_SIZE
,
preference
.
getInt
(
Preference
.
ARTICLE_LIST_PAGINATION_WINDOW_SIZE
));
dataModel
.
put
(
Preference
.
LOCALE_STRING
,
preference
.
getString
(
Preference
.
LOCALE_STRING
));
dataModel
.
put
(
Preference
.
BLOG_TITLE
,
preference
.
getString
(
Preference
.
BLOG_TITLE
));
dataModel
.
put
(
Preference
.
BLOG_SUBTITLE
,
preference
.
getString
(
Preference
.
BLOG_SUBTITLE
));
dataModel
.
put
(
Preference
.
HTML_HEAD
,
preference
.
getString
(
Preference
.
HTML_HEAD
));
dataModel
.
put
(
Preference
.
META_KEYWORDS
,
preference
.
getString
(
Preference
.
META_KEYWORDS
));
dataModel
.
put
(
Preference
.
META_DESCRIPTION
,
preference
.
getString
(
Preference
.
META_DESCRIPTION
));
dataModel
.
put
(
Common
.
YEAR
,
String
.
valueOf
(
Calendar
.
getInstance
().
get
(
Calendar
.
YEAR
)));
final
String
noticeBoard
=
preference
.
getString
(
Preference
.
NOTICE_BOARD
);
dataModel
.
put
(
Preference
.
NOTICE_BOARD
,
noticeBoard
);
final
Query
query
=
new
Query
().
setPageCount
(
1
);
final
JSONObject
result
=
userRepository
.
get
(
query
);
final
JSONArray
users
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
final
List
<
JSONObject
>
userList
=
CollectionUtils
.
jsonArrayToList
(
users
);
dataModel
.
put
(
User
.
USERS
,
userList
);
for
(
final
JSONObject
user
:
userList
)
{
user
.
remove
(
User
.
USER_EMAIL
);
}
final
String
skinDirName
=
(
String
)
request
.
getAttribute
(
Keys
.
TEMAPLTE_DIR_NAME
);
dataModel
.
put
(
Skin
.
SKIN_DIR_NAME
,
skinDirName
);
Keys
.
fillServer
(
dataModel
);
fillMinified
(
dataModel
);
fillPageNavigations
(
dataModel
);
fillStatistic
(
dataModel
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills blog header failed"
,
e
);
throw
new
ServiceException
(
e
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills blog header failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills minified directory and file postfix for static JavaScript, CSS.
*
* @param dataModel the specified data model
*/
public
void
fillMinified
(
final
Map
<
String
,
Object
>
dataModel
)
{
switch
(
Latkes
.
getRuntimeMode
())
{
case
DEVELOPMENT:
dataModel
.
put
(
Common
.
MINI_POSTFIX
,
""
);
break
;
case
PRODUCTION:
dataModel
.
put
(
Common
.
MINI_POSTFIX
,
Common
.
MINI_POSTFIX_VALUE
);
break
;
default
:
throw
new
AssertionError
();
}
}
/**
* Fills side.ftl.
*
* @param request the specified HTTP servlet request
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillSide
(
final
HttpServletRequest
request
,
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Side"
);
try
{
LOGGER
.
fine
(
"Filling side...."
);
final
Template
template
=
Templates
.
getTemplate
((
String
)
request
.
getAttribute
(
Keys
.
TEMAPLTE_DIR_NAME
),
"side.ftl"
);
if
(
null
==
template
)
{
LOGGER
.
fine
(
"The skin dose not contain [side.ftl] template"
);
return
;
}
// TODO: fillRecentArticles(dataModel, preference);
if
(
Templates
.
hasExpression
(
template
,
"<#list links as link>"
))
{
fillLinks
(
dataModel
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list recentComments as comment>"
))
{
fillRecentComments
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list mostUsedTags as tag>"
))
{
fillMostUsedTags
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list mostCommentArticles as article>"
))
{
fillMostCommentArticles
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list mostViewCountArticles as article>"
))
{
fillMostViewCountArticles
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list archiveDates as archiveDate>"
))
{
fillArchiveDates
(
dataModel
,
preference
);
}
}
catch
(
final
ServiceException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills side failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills the specified template.
*
* @param template the specified template
* @param dataModel data model
* @param preference the specified preference
* @throws ServiceException service exception
*/
public
void
fillUserTemplate
(
final
Template
template
,
final
Map
<
String
,
Object
>
dataModel
,
final
JSONObject
preference
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill User Template[name="
+
template
.
getName
()
+
"]"
);
try
{
LOGGER
.
log
(
Level
.
FINE
,
"Filling user template[name{0}]"
,
template
.
getName
());
if
(
Templates
.
hasExpression
(
template
,
"<#list links as link>"
))
{
fillLinks
(
dataModel
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list recentComments as comment>"
))
{
fillRecentComments
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list mostUsedTags as tag>"
))
{
fillMostUsedTags
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list mostCommentArticles as article>"
))
{
fillMostCommentArticles
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list mostViewCountArticles as article>"
))
{
fillMostViewCountArticles
(
dataModel
,
preference
);
}
if
(
Templates
.
hasExpression
(
template
,
"<#list archiveDates as archiveDate>"
))
{
fillArchiveDates
(
dataModel
,
preference
);
}
final
String
noticeBoard
=
preference
.
getString
(
Preference
.
NOTICE_BOARD
);
dataModel
.
put
(
Preference
.
NOTICE_BOARD
,
noticeBoard
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills user template failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills page navigations.
*
* @param dataModel data model
* @throws ServiceException service exception
*/
private
void
fillPageNavigations
(
final
Map
<
String
,
Object
>
dataModel
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Navigations"
);
try
{
LOGGER
.
finer
(
"Filling page navigations...."
);
final
List
<
JSONObject
>
pages
=
pageRepository
.
getPages
();
for
(
final
JSONObject
page
:
pages
)
{
if
(
"page"
.
equals
(
page
.
optString
(
Page
.
PAGE_TYPE
)))
{
final
String
permalink
=
page
.
optString
(
Page
.
PAGE_PERMALINK
);
page
.
put
(
Page
.
PAGE_PERMALINK
,
Latkes
.
getServePath
()
+
permalink
);
}
}
dataModel
.
put
(
Common
.
PAGE_NAVIGATIONS
,
pages
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills page navigations failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Fills statistic.
*
* @param dataModel data model
* @throws ServiceException service exception
*/
private
void
fillStatistic
(
final
Map
<
String
,
Object
>
dataModel
)
throws
ServiceException
{
Stopwatchs
.
start
(
"Fill Statistic"
);
try
{
LOGGER
.
finer
(
"Filling statistic...."
);
final
JSONObject
statistic
=
statisticRepository
.
get
(
Statistic
.
STATISTIC
);
dataModel
.
put
(
Statistic
.
STATISTIC
,
statistic
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Fills statistic failed"
,
e
);
throw
new
ServiceException
(
e
);
}
finally
{
Stopwatchs
.
end
();
}
}
/**
* Sets some extra properties into the specified article with the specified author and preference, performs content and
* abstract editor processing.
*
* <p>
* Article ext properties:
* <pre>
* {
* ....,
* "authorName": "",
* "authorId": "",
* "hasUpdated": boolean
* }
* </pre>
* </p>
*
* @param article the specified article
* @param author the specified author
* @param preference the specified preference
* @throws ServiceException service exception
* @see #setArticlesExProperties(java.util.List, org.json.JSONObject)
*/
private
void
setArticleExProperties
(
final
JSONObject
article
,
final
JSONObject
author
,
final
JSONObject
preference
)
throws
ServiceException
{
try
{
final
String
authorName
=
author
.
getString
(
User
.
USER_NAME
);
article
.
put
(
Common
.
AUTHOR_NAME
,
authorName
);
final
String
authorId
=
author
.
getString
(
Keys
.
OBJECT_ID
);
article
.
put
(
Common
.
AUTHOR_ID
,
authorId
);
if
(
preference
.
getBoolean
(
Preference
.
ENABLE_ARTICLE_UPDATE_HINT
))
{
article
.
put
(
Common
.
HAS_UPDATED
,
articleUtils
.
hasUpdated
(
article
));
}
else
{
article
.
put
(
Common
.
HAS_UPDATED
,
false
);
}
processArticleAbstract
(
preference
,
article
);
articleQueryService
.
markdown
(
article
);
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Sets article extra properties failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Sets some extra properties into the specified article with the specified preference, performs content and
* abstract editor processing.
*
* <p>
* Article ext properties:
* <pre>
* {
* ....,
* "authorName": "",
* "authorId": "",
* "hasUpdated": boolean
* }
* </pre>
* </p>
*
* @param article the specified article
* @param preference the specified preference
* @throws ServiceException service exception
* @see #setArticlesExProperties(java.util.List, org.json.JSONObject)
*/
private
void
setArticleExProperties
(
final
JSONObject
article
,
final
JSONObject
preference
)
throws
ServiceException
{
try
{
final
JSONObject
author
=
articleUtils
.
getAuthor
(
article
);
final
String
authorName
=
author
.
getString
(
User
.
USER_NAME
);
article
.
put
(
Common
.
AUTHOR_NAME
,
authorName
);
final
String
authorId
=
author
.
getString
(
Keys
.
OBJECT_ID
);
article
.
put
(
Common
.
AUTHOR_ID
,
authorId
);
if
(
preference
.
getBoolean
(
Preference
.
ENABLE_ARTICLE_UPDATE_HINT
))
{
article
.
put
(
Common
.
HAS_UPDATED
,
articleUtils
.
hasUpdated
(
article
));
}
else
{
article
.
put
(
Common
.
HAS_UPDATED
,
false
);
}
processArticleAbstract
(
preference
,
article
);
articleQueryService
.
markdown
(
article
);
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Sets article extra properties failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Sets some extra properties into the specified article with the specified
* author and preference.
*
* <p>
* The batch version of method
* {@linkplain #setArticleExProperties(org.json.JSONObject, org.json.JSONObject)}.
* </p>
*
* <p>
* Article ext properties:
* <pre>
* {
* ....,
* "authorName": "",
* "authorId": "",
* "hasUpdated": boolean
* }
* </pre>
* </p>
*
* @param articles the specified articles
* @param author the specified author
* @param preference the specified preference
* @throws ServiceException service exception
* @see #setArticleExProperties(org.json.JSONObject, org.json.JSONObject)
*/
public
void
setArticlesExProperties
(
final
List
<
JSONObject
>
articles
,
final
JSONObject
author
,
final
JSONObject
preference
)
throws
ServiceException
{
for
(
final
JSONObject
article
:
articles
)
{
setArticleExProperties
(
article
,
author
,
preference
);
}
}
/**
* Sets some extra properties into the specified article with the specified
* preference.
*
* <p>
* The batch version of method
* {@linkplain #setArticleExProperties(org.json.JSONObject, org.json.JSONObject)}.
* </p>
*
* <p>
* Article ext properties:
* <pre>
* {
* ....,
* "authorName": "",
* "authorId": "",
* "hasUpdated": boolean
* }
* </pre>
* </p>
*
* @param articles the specified articles
* @param preference the specified preference
* @throws ServiceException service exception
* @see #setArticleExProperties(org.json.JSONObject, org.json.JSONObject)
*/
public
void
setArticlesExProperties
(
final
List
<
JSONObject
>
articles
,
final
JSONObject
preference
)
throws
ServiceException
{
for
(
final
JSONObject
article
:
articles
)
{
setArticleExProperties
(
article
,
preference
);
}
}
/**
* Processes the abstract of the specified article with the specified preference.
*
* <p>
* <ul>
* <li>If the abstract is {@code null}, sets it with ""</li>
* <li>If user configured preference "titleOnly", sets the abstract with ""</li>
* <li>If user configured preference "titleAndContent", sets the abstract with the content of the article</li>
* </ul>
* </p>
*
* @param preference the specified preference
* @param article the specified article
*/
private
void
processArticleAbstract
(
final
JSONObject
preference
,
final
JSONObject
article
)
{
final
String
articleAbstract
=
article
.
optString
(
Article
.
ARTICLE_ABSTRACT
,
null
);
if
(
null
==
articleAbstract
)
{
article
.
put
(
Article
.
ARTICLE_ABSTRACT
,
""
);
}
final
String
articleListStyle
=
preference
.
optString
(
Preference
.
ARTICLE_LIST_STYLE
);
if
(
"titleOnly"
.
equals
(
articleListStyle
))
{
article
.
put
(
Article
.
ARTICLE_ABSTRACT
,
""
);
}
else
if
(
"titleAndContent"
.
equals
(
articleListStyle
))
{
article
.
put
(
Article
.
ARTICLE_ABSTRACT
,
article
.
optString
(
Article
.
ARTICLE_CONTENT
));
}
}
/**
* Gets the {@link Filler} singleton.
*
* @return the singleton
*/
public
static
Filler
getInstance
()
{
return
SingletonHolder
.
SINGLETON
;
}
/**
* Private default constructor.
*/
private
Filler
()
{
}
/**
* Singleton holder.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Jan 12, 2011
*/
private
static
final
class
SingletonHolder
{
/**
* Singleton.
*/
private
static
final
Filler
SINGLETON
=
new
Filler
();
/**
* Private default constructor.
*/
private
SingletonHolder
()
{
}
}
}
core/src/main/java/org/b3log/solo/repository/impl/ArchiveDateArticleRepositoryImpl.java
View file @
4af1a1bb
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.AbstractRepository
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.Query
;
import
org.b3log.solo.model.Article
;
import
org.b3log.latke.repository.RepositoryException
;
import
org.b3log.latke.repository.SortDirection
;
import
org.b3log.solo.model.ArchiveDate
;
import
org.b3log.solo.repository.ArchiveDateArticleRepository
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Archive date-Article relation repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.6, Nov 9, 2011
* @since 0.3.1
*/
public
final
class
ArchiveDateArticleRepositoryImpl
extends
AbstractRepository
implements
ArchiveDateArticleRepository
{
/**
* Singleton.
*/
private
static
final
ArchiveDateArticleRepositoryImpl
SINGLETON
=
new
ArchiveDateArticleRepositoryImpl
(
ArchiveDate
.
ARCHIVE_DATE
+
"_"
+
Article
.
ARTICLE
);
@Override
public
JSONObject
getByArchiveDateId
(
final
String
archiveDateId
,
final
int
currentPageNum
,
final
int
pageSize
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addFilter
(
ArchiveDate
.
ARCHIVE_DATE
+
"_"
+
Keys
.
OBJECT_ID
,
FilterOperator
.
EQUAL
,
archiveDateId
).
addSort
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
,
SortDirection
.
DESCENDING
).
setCurrentPageNum
(
currentPageNum
).
setPageSize
(
pageSize
).
setPageCount
(
1
);
return
get
(
query
);
}
@Override
public
JSONObject
getByArticleId
(
final
String
articleId
)
throws
RepositoryException
{
final
Query
query
=
new
Query
();
query
.
addFilter
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
,
FilterOperator
.
EQUAL
,
articleId
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
/**
* Gets the {@link ArchiveDateArticleRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
ArchiveDateArticleRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
ArchiveDateArticleRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.*
;
import
org.b3log.solo.model.Article
;
import
org.b3log.solo.model.ArchiveDate
;
import
org.b3log.solo.repository.ArchiveDateArticleRepository
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Archive date-Article relation repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.6, Nov 9, 2011
* @since 0.3.1
*/
public
final
class
ArchiveDateArticleRepositoryImpl
extends
AbstractRepository
implements
ArchiveDateArticleRepository
{
/**
* Singleton.
*/
private
static
final
ArchiveDateArticleRepositoryImpl
SINGLETON
=
new
ArchiveDateArticleRepositoryImpl
(
ArchiveDate
.
ARCHIVE_DATE
+
"_"
+
Article
.
ARTICLE
);
@Override
public
JSONObject
getByArchiveDateId
(
final
String
archiveDateId
,
final
int
currentPageNum
,
final
int
pageSize
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
setFilter
(
new
PropertyFilter
(
ArchiveDate
.
ARCHIVE_DATE
+
"_"
+
Keys
.
OBJECT_ID
,
FilterOperator
.
EQUAL
,
archiveDateId
)).
addSort
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
,
SortDirection
.
DESCENDING
).
setCurrentPageNum
(
currentPageNum
).
setPageSize
(
pageSize
).
setPageCount
(
1
);
return
get
(
query
);
}
@Override
public
JSONObject
getByArticleId
(
final
String
articleId
)
throws
RepositoryException
{
final
Query
query
=
new
Query
();
query
.
setFilter
(
new
PropertyFilter
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
,
FilterOperator
.
EQUAL
,
articleId
));
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
/**
* Gets the {@link ArchiveDateArticleRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
ArchiveDateArticleRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
ArchiveDateArticleRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
core/src/main/java/org/b3log/solo/repository/impl/ArchiveDateRepositoryImpl.java
View file @
4af1a1bb
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.text.ParseException
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.AbstractRepository
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.Query
;
import
org.b3log.latke.repository.RepositoryException
;
import
org.b3log.latke.repository.SortDirection
;
import
org.b3log.latke.util.CollectionUtils
;
import
org.b3log.solo.model.ArchiveDate
;
import
org.b3log.solo.repository.ArchiveDateRepository
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Archive date repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.6, Dec 31, 2011
* @since 0.3.1
*/
public
final
class
ArchiveDateRepositoryImpl
extends
AbstractRepository
implements
ArchiveDateRepository
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
ArchiveDateRepositoryImpl
.
class
.
getName
());
/**
* Singleton.
*/
private
static
final
ArchiveDateRepositoryImpl
SINGLETON
=
new
ArchiveDateRepositoryImpl
(
ArchiveDate
.
ARCHIVE_DATE
);
@Override
public
JSONObject
getByArchiveDate
(
final
String
archiveDate
)
throws
RepositoryException
{
long
time
=
0L
;
try
{
time
=
ArchiveDate
.
DATE_FORMAT
.
parse
(
archiveDate
).
getTime
();
}
catch
(
final
ParseException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Can not parse archive date ["
+
archiveDate
+
"]"
,
e
);
throw
new
RepositoryException
(
"Can not parse archive date ["
+
archiveDate
+
"]"
);
}
final
Query
query
=
new
Query
();
query
.
addFilter
(
ArchiveDate
.
ARCHIVE_TIME
,
FilterOperator
.
EQUAL
,
time
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
List
<
JSONObject
>
getArchiveDates
()
throws
RepositoryException
{
final
org
.
b3log
.
latke
.
repository
.
Query
query
=
new
Query
().
addSort
(
ArchiveDate
.
ARCHIVE_TIME
,
SortDirection
.
DESCENDING
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
archiveDates
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
final
List
<
JSONObject
>
ret
=
CollectionUtils
.
jsonArrayToList
(
archiveDates
);
removeForUnpublishedArticles
(
ret
);
return
ret
;
}
/**
* Removes archive dates of unpublished articles from the specified archive
* dates.
*
* @param archiveDates the specified archive dates
* @throws RepositoryException repository exception
*/
private
void
removeForUnpublishedArticles
(
final
List
<
JSONObject
>
archiveDates
)
throws
RepositoryException
{
final
Iterator
<
JSONObject
>
iterator
=
archiveDates
.
iterator
();
while
(
iterator
.
hasNext
())
{
final
JSONObject
archiveDate
=
iterator
.
next
();
if
(
0
==
archiveDate
.
optInt
(
ArchiveDate
.
ARCHIVE_DATE_PUBLISHED_ARTICLE_COUNT
))
{
iterator
.
remove
();
}
}
}
/**
* Gets the {@link ArchiveDateRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
ArchiveDateRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
ArchiveDateRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.text.ParseException
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.*
;
import
org.b3log.latke.util.CollectionUtils
;
import
org.b3log.solo.model.ArchiveDate
;
import
org.b3log.solo.repository.ArchiveDateRepository
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Archive date repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.6, Dec 31, 2011
* @since 0.3.1
*/
public
final
class
ArchiveDateRepositoryImpl
extends
AbstractRepository
implements
ArchiveDateRepository
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
ArchiveDateRepositoryImpl
.
class
.
getName
());
/**
* Singleton.
*/
private
static
final
ArchiveDateRepositoryImpl
SINGLETON
=
new
ArchiveDateRepositoryImpl
(
ArchiveDate
.
ARCHIVE_DATE
);
@Override
public
JSONObject
getByArchiveDate
(
final
String
archiveDate
)
throws
RepositoryException
{
long
time
=
0L
;
try
{
time
=
ArchiveDate
.
DATE_FORMAT
.
parse
(
archiveDate
).
getTime
();
}
catch
(
final
ParseException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Can not parse archive date ["
+
archiveDate
+
"]"
,
e
);
throw
new
RepositoryException
(
"Can not parse archive date ["
+
archiveDate
+
"]"
);
}
final
Query
query
=
new
Query
();
query
.
setFilter
(
new
PropertyFilter
(
ArchiveDate
.
ARCHIVE_TIME
,
FilterOperator
.
EQUAL
,
time
)).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
List
<
JSONObject
>
getArchiveDates
()
throws
RepositoryException
{
final
org
.
b3log
.
latke
.
repository
.
Query
query
=
new
Query
().
addSort
(
ArchiveDate
.
ARCHIVE_TIME
,
SortDirection
.
DESCENDING
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
archiveDates
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
final
List
<
JSONObject
>
ret
=
CollectionUtils
.
jsonArrayToList
(
archiveDates
);
removeForUnpublishedArticles
(
ret
);
return
ret
;
}
/**
* Removes archive dates of unpublished articles from the specified archive
* dates.
*
* @param archiveDates the specified archive dates
* @throws RepositoryException repository exception
*/
private
void
removeForUnpublishedArticles
(
final
List
<
JSONObject
>
archiveDates
)
throws
RepositoryException
{
final
Iterator
<
JSONObject
>
iterator
=
archiveDates
.
iterator
();
while
(
iterator
.
hasNext
())
{
final
JSONObject
archiveDate
=
iterator
.
next
();
if
(
0
==
archiveDate
.
optInt
(
ArchiveDate
.
ARCHIVE_DATE_PUBLISHED_ARTICLE_COUNT
))
{
iterator
.
remove
();
}
}
}
/**
* Gets the {@link ArchiveDateRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
ArchiveDateRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
ArchiveDateRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
core/src/main/java/org/b3log/solo/repository/impl/ArticleRepositoryImpl.java
View file @
4af1a1bb
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.util.ArrayList
;
import
java.util.Date
;
import
java.util.List
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
org.b3log.solo.model.Article
;
import
org.b3log.solo.repository.ArticleRepository
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.*
;
import
org.b3log.latke.util.CollectionUtils
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
/**
* Article repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.3.9, May 8, 2012
* @since 0.3.1
*/
public
final
class
ArticleRepositoryImpl
extends
AbstractRepository
implements
ArticleRepository
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
ArticleRepositoryImpl
.
class
.
getName
());
/**
* Singleton.
*/
private
static
final
ArticleRepositoryImpl
SINGLETON
=
new
ArticleRepositoryImpl
(
Article
.
ARTICLE
);
/**
* Random range.
*/
private
static
final
double
RANDOM_RANGE
=
0.1
D
;
@Override
public
JSONObject
getByAuthorEmail
(
final
String
authorEmail
,
final
int
currentPageNum
,
final
int
pageSize
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addFilter
(
Article
.
ARTICLE_AUTHOR_EMAIL
,
FilterOperator
.
EQUAL
,
authorEmail
).
addFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
).
addSort
(
Article
.
ARTICLE_UPDATE_DATE
,
SortDirection
.
DESCENDING
).
setCurrentPageNum
(
currentPageNum
).
setPageSize
(
pageSize
).
setPageCount
(
1
);
return
get
(
query
);
}
@Override
public
JSONObject
getByPermalink
(
final
String
permalink
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addFilter
(
Article
.
ARTICLE_PERMALINK
,
FilterOperator
.
EQUAL
,
permalink
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
List
<
JSONObject
>
getRecentArticles
(
final
int
fetchSize
)
throws
RepositoryException
{
final
Query
query
=
new
Query
();
query
.
addFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
);
query
.
addSort
(
Article
.
ARTICLE_UPDATE_DATE
,
SortDirection
.
DESCENDING
);
query
.
setCurrentPageNum
(
1
);
query
.
setPageSize
(
fetchSize
);
query
.
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
return
CollectionUtils
.
jsonArrayToList
(
array
);
}
@Override
public
List
<
JSONObject
>
getMostCommentArticles
(
final
int
num
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addSort
(
Article
.
ARTICLE_COMMENT_COUNT
,
SortDirection
.
DESCENDING
).
addSort
(
Article
.
ARTICLE_UPDATE_DATE
,
SortDirection
.
DESCENDING
).
addFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
).
setCurrentPageNum
(
1
).
setPageSize
(
num
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
return
CollectionUtils
.
jsonArrayToList
(
array
);
}
@Override
public
List
<
JSONObject
>
getMostViewCountArticles
(
final
int
num
)
throws
RepositoryException
{
final
Query
query
=
new
Query
();
query
.
addSort
(
Article
.
ARTICLE_VIEW_COUNT
,
SortDirection
.
DESCENDING
).
addSort
(
Article
.
ARTICLE_UPDATE_DATE
,
SortDirection
.
DESCENDING
);
query
.
addFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
);
query
.
setCurrentPageNum
(
1
);
query
.
setPageSize
(
num
);
query
.
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
return
CollectionUtils
.
jsonArrayToList
(
array
);
}
@Override
public
JSONObject
getPreviousArticle
(
final
String
articleId
)
throws
RepositoryException
{
final
JSONObject
currentArticle
=
get
(
articleId
);
final
Date
currentArticleCreateDate
=
(
Date
)
currentArticle
.
opt
(
Article
.
ARTICLE_CREATE_DATE
);
final
Query
query
=
new
Query
().
addFilter
(
Article
.
ARTICLE_CREATE_DATE
,
FilterOperator
.
LESS_THAN
,
currentArticleCreateDate
).
addFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
).
addSort
(
Article
.
ARTICLE_CREATE_DATE
,
SortDirection
.
DESCENDING
).
setCurrentPageNum
(
1
).
setPageSize
(
1
).
setPageCount
(
1
).
addProjection
(
Article
.
ARTICLE_TITLE
,
String
.
class
).
addProjection
(
Article
.
ARTICLE_PERMALINK
,
String
.
class
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
1
!=
array
.
length
())
{
return
null
;
}
final
JSONObject
ret
=
new
JSONObject
();
final
JSONObject
article
=
array
.
optJSONObject
(
0
);
try
{
ret
.
put
(
Article
.
ARTICLE_TITLE
,
article
.
getString
(
Article
.
ARTICLE_TITLE
));
ret
.
put
(
Article
.
ARTICLE_PERMALINK
,
article
.
getString
(
Article
.
ARTICLE_PERMALINK
));
}
catch
(
final
JSONException
e
)
{
throw
new
RepositoryException
(
e
);
}
return
ret
;
}
@Override
public
JSONObject
getNextArticle
(
final
String
articleId
)
throws
RepositoryException
{
final
JSONObject
currentArticle
=
get
(
articleId
);
final
Date
currentArticleCreateDate
=
(
Date
)
currentArticle
.
opt
(
Article
.
ARTICLE_CREATE_DATE
);
final
Query
query
=
new
Query
().
addFilter
(
Article
.
ARTICLE_CREATE_DATE
,
FilterOperator
.
GREATER_THAN
,
currentArticleCreateDate
).
addFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
).
addSort
(
Article
.
ARTICLE_CREATE_DATE
,
SortDirection
.
ASCENDING
).
setCurrentPageNum
(
1
).
setPageSize
(
1
).
setPageCount
(
1
).
addProjection
(
Article
.
ARTICLE_TITLE
,
String
.
class
).
addProjection
(
Article
.
ARTICLE_PERMALINK
,
String
.
class
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
1
!=
array
.
length
())
{
return
null
;
}
final
JSONObject
ret
=
new
JSONObject
();
final
JSONObject
article
=
array
.
optJSONObject
(
0
);
try
{
ret
.
put
(
Article
.
ARTICLE_TITLE
,
article
.
getString
(
Article
.
ARTICLE_TITLE
));
ret
.
put
(
Article
.
ARTICLE_PERMALINK
,
article
.
getString
(
Article
.
ARTICLE_PERMALINK
));
}
catch
(
final
JSONException
e
)
{
throw
new
RepositoryException
(
e
);
}
return
ret
;
}
@Override
public
boolean
isPublished
(
final
String
articleId
)
throws
RepositoryException
{
final
JSONObject
article
=
get
(
articleId
);
if
(
null
==
article
)
{
return
false
;
}
return
article
.
optBoolean
(
Article
.
ARTICLE_IS_PUBLISHED
);
}
@Override
public
List
<
JSONObject
>
getRandomly
(
final
int
fetchSize
)
throws
RepositoryException
{
final
List
<
JSONObject
>
ret
=
new
ArrayList
<
JSONObject
>();
if
(
0
==
count
())
{
return
ret
;
}
final
double
mid
=
Math
.
random
()
+
RANDOM_RANGE
;
LOGGER
.
log
(
Level
.
FINEST
,
"Random mid[{0}]"
,
mid
);
Query
query
=
new
Query
();
query
.
addFilter
(
Article
.
ARTICLE_RANDOM_DOUBLE
,
FilterOperator
.
GREATER_THAN_OR_EQUAL
,
mid
);
query
.
addFilter
(
Article
.
ARTICLE_RANDOM_DOUBLE
,
FilterOperator
.
LESS_THAN_OR_EQUAL
,
mid
);
query
.
addFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
);
query
.
setCurrentPageNum
(
1
);
query
.
setPageSize
(
fetchSize
);
query
.
setPageCount
(
1
);
final
JSONObject
result1
=
get
(
query
);
final
JSONArray
array1
=
result1
.
optJSONArray
(
Keys
.
RESULTS
);
final
List
<
JSONObject
>
list1
=
CollectionUtils
.<
JSONObject
>
jsonArrayToList
(
array1
);
ret
.
addAll
(
list1
);
final
int
reminingSize
=
fetchSize
-
array1
.
length
();
if
(
0
!=
reminingSize
)
{
// Query for remains
query
=
new
Query
();
query
.
addFilter
(
Article
.
ARTICLE_RANDOM_DOUBLE
,
FilterOperator
.
GREATER_THAN_OR_EQUAL
,
0
D
);
query
.
addFilter
(
Article
.
ARTICLE_RANDOM_DOUBLE
,
FilterOperator
.
LESS_THAN_OR_EQUAL
,
mid
);
query
.
addFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
);
query
.
setCurrentPageNum
(
1
);
query
.
setPageSize
(
reminingSize
);
query
.
setPageCount
(
1
);
final
JSONObject
result2
=
get
(
query
);
final
JSONArray
array2
=
result2
.
optJSONArray
(
Keys
.
RESULTS
);
final
List
<
JSONObject
>
list2
=
CollectionUtils
.<
JSONObject
>
jsonArrayToList
(
array2
);
ret
.
addAll
(
list2
);
}
return
ret
;
}
/**
* Gets the {@link ArticleRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
ArticleRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
ArticleRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.util.ArrayList
;
import
java.util.Date
;
import
java.util.List
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
org.b3log.solo.model.Article
;
import
org.b3log.solo.repository.ArticleRepository
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.*
;
import
org.b3log.latke.util.CollectionUtils
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
/**
* Article repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.3.9, May 8, 2012
* @since 0.3.1
*/
public
final
class
ArticleRepositoryImpl
extends
AbstractRepository
implements
ArticleRepository
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
ArticleRepositoryImpl
.
class
.
getName
());
/**
* Singleton.
*/
private
static
final
ArticleRepositoryImpl
SINGLETON
=
new
ArticleRepositoryImpl
(
Article
.
ARTICLE
);
/**
* Random range.
*/
private
static
final
double
RANDOM_RANGE
=
0.1
D
;
@Override
public
JSONObject
getByAuthorEmail
(
final
String
authorEmail
,
final
int
currentPageNum
,
final
int
pageSize
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
setFilter
(
CompositeFilterOperator
.
and
(
new
PropertyFilter
(
Article
.
ARTICLE_AUTHOR_EMAIL
,
FilterOperator
.
EQUAL
,
authorEmail
),
new
PropertyFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
))).
addSort
(
Article
.
ARTICLE_UPDATE_DATE
,
SortDirection
.
DESCENDING
).
setCurrentPageNum
(
currentPageNum
).
setPageSize
(
pageSize
).
setPageCount
(
1
);
return
get
(
query
);
}
@Override
public
JSONObject
getByPermalink
(
final
String
permalink
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
setFilter
(
new
PropertyFilter
(
Article
.
ARTICLE_PERMALINK
,
FilterOperator
.
EQUAL
,
permalink
)).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
List
<
JSONObject
>
getRecentArticles
(
final
int
fetchSize
)
throws
RepositoryException
{
final
Query
query
=
new
Query
();
query
.
setFilter
(
new
PropertyFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
));
query
.
addSort
(
Article
.
ARTICLE_UPDATE_DATE
,
SortDirection
.
DESCENDING
);
query
.
setCurrentPageNum
(
1
);
query
.
setPageSize
(
fetchSize
);
query
.
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
return
CollectionUtils
.
jsonArrayToList
(
array
);
}
@Override
public
List
<
JSONObject
>
getMostCommentArticles
(
final
int
num
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addSort
(
Article
.
ARTICLE_COMMENT_COUNT
,
SortDirection
.
DESCENDING
).
addSort
(
Article
.
ARTICLE_UPDATE_DATE
,
SortDirection
.
DESCENDING
).
setFilter
(
new
PropertyFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
)).
setCurrentPageNum
(
1
).
setPageSize
(
num
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
return
CollectionUtils
.
jsonArrayToList
(
array
);
}
@Override
public
List
<
JSONObject
>
getMostViewCountArticles
(
final
int
num
)
throws
RepositoryException
{
final
Query
query
=
new
Query
();
query
.
addSort
(
Article
.
ARTICLE_VIEW_COUNT
,
SortDirection
.
DESCENDING
).
addSort
(
Article
.
ARTICLE_UPDATE_DATE
,
SortDirection
.
DESCENDING
);
query
.
setFilter
(
new
PropertyFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
));
query
.
setCurrentPageNum
(
1
);
query
.
setPageSize
(
num
);
query
.
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
return
CollectionUtils
.
jsonArrayToList
(
array
);
}
@Override
public
JSONObject
getPreviousArticle
(
final
String
articleId
)
throws
RepositoryException
{
final
JSONObject
currentArticle
=
get
(
articleId
);
final
Date
currentArticleCreateDate
=
(
Date
)
currentArticle
.
opt
(
Article
.
ARTICLE_CREATE_DATE
);
final
Query
query
=
new
Query
().
setFilter
(
CompositeFilterOperator
.
and
(
new
PropertyFilter
(
Article
.
ARTICLE_CREATE_DATE
,
FilterOperator
.
LESS_THAN
,
currentArticleCreateDate
),
new
PropertyFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
))).
addSort
(
Article
.
ARTICLE_CREATE_DATE
,
SortDirection
.
DESCENDING
).
setCurrentPageNum
(
1
).
setPageSize
(
1
).
setPageCount
(
1
).
addProjection
(
Article
.
ARTICLE_TITLE
,
String
.
class
).
addProjection
(
Article
.
ARTICLE_PERMALINK
,
String
.
class
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
1
!=
array
.
length
())
{
return
null
;
}
final
JSONObject
ret
=
new
JSONObject
();
final
JSONObject
article
=
array
.
optJSONObject
(
0
);
try
{
ret
.
put
(
Article
.
ARTICLE_TITLE
,
article
.
getString
(
Article
.
ARTICLE_TITLE
));
ret
.
put
(
Article
.
ARTICLE_PERMALINK
,
article
.
getString
(
Article
.
ARTICLE_PERMALINK
));
}
catch
(
final
JSONException
e
)
{
throw
new
RepositoryException
(
e
);
}
return
ret
;
}
@Override
public
JSONObject
getNextArticle
(
final
String
articleId
)
throws
RepositoryException
{
final
JSONObject
currentArticle
=
get
(
articleId
);
final
Date
currentArticleCreateDate
=
(
Date
)
currentArticle
.
opt
(
Article
.
ARTICLE_CREATE_DATE
);
final
Query
query
=
new
Query
().
setFilter
(
CompositeFilterOperator
.
and
(
new
PropertyFilter
(
Article
.
ARTICLE_CREATE_DATE
,
FilterOperator
.
GREATER_THAN
,
currentArticleCreateDate
),
new
PropertyFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
))).
addSort
(
Article
.
ARTICLE_CREATE_DATE
,
SortDirection
.
ASCENDING
).
setCurrentPageNum
(
1
).
setPageSize
(
1
).
setPageCount
(
1
).
addProjection
(
Article
.
ARTICLE_TITLE
,
String
.
class
).
addProjection
(
Article
.
ARTICLE_PERMALINK
,
String
.
class
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
1
!=
array
.
length
())
{
return
null
;
}
final
JSONObject
ret
=
new
JSONObject
();
final
JSONObject
article
=
array
.
optJSONObject
(
0
);
try
{
ret
.
put
(
Article
.
ARTICLE_TITLE
,
article
.
getString
(
Article
.
ARTICLE_TITLE
));
ret
.
put
(
Article
.
ARTICLE_PERMALINK
,
article
.
getString
(
Article
.
ARTICLE_PERMALINK
));
}
catch
(
final
JSONException
e
)
{
throw
new
RepositoryException
(
e
);
}
return
ret
;
}
@Override
public
boolean
isPublished
(
final
String
articleId
)
throws
RepositoryException
{
final
JSONObject
article
=
get
(
articleId
);
if
(
null
==
article
)
{
return
false
;
}
return
article
.
optBoolean
(
Article
.
ARTICLE_IS_PUBLISHED
);
}
@Override
public
List
<
JSONObject
>
getRandomly
(
final
int
fetchSize
)
throws
RepositoryException
{
final
List
<
JSONObject
>
ret
=
new
ArrayList
<
JSONObject
>();
if
(
0
==
count
())
{
return
ret
;
}
final
double
mid
=
Math
.
random
()
+
RANDOM_RANGE
;
LOGGER
.
log
(
Level
.
FINEST
,
"Random mid[{0}]"
,
mid
);
Query
query
=
new
Query
();
query
.
setFilter
(
CompositeFilterOperator
.
and
(
new
PropertyFilter
(
Article
.
ARTICLE_RANDOM_DOUBLE
,
FilterOperator
.
GREATER_THAN_OR_EQUAL
,
mid
),
new
PropertyFilter
(
Article
.
ARTICLE_RANDOM_DOUBLE
,
FilterOperator
.
LESS_THAN_OR_EQUAL
,
mid
),
new
PropertyFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
)));
query
.
setCurrentPageNum
(
1
);
query
.
setPageSize
(
fetchSize
);
query
.
setPageCount
(
1
);
final
JSONObject
result1
=
get
(
query
);
final
JSONArray
array1
=
result1
.
optJSONArray
(
Keys
.
RESULTS
);
final
List
<
JSONObject
>
list1
=
CollectionUtils
.<
JSONObject
>
jsonArrayToList
(
array1
);
ret
.
addAll
(
list1
);
final
int
reminingSize
=
fetchSize
-
array1
.
length
();
if
(
0
!=
reminingSize
)
{
// Query for remains
query
=
new
Query
();
query
.
setFilter
(
CompositeFilterOperator
.
and
(
new
PropertyFilter
(
Article
.
ARTICLE_RANDOM_DOUBLE
,
FilterOperator
.
GREATER_THAN_OR_EQUAL
,
0
D
),
new
PropertyFilter
(
Article
.
ARTICLE_RANDOM_DOUBLE
,
FilterOperator
.
LESS_THAN_OR_EQUAL
,
mid
),
new
PropertyFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
)));
query
.
setCurrentPageNum
(
1
);
query
.
setPageSize
(
reminingSize
);
query
.
setPageCount
(
1
);
final
JSONObject
result2
=
get
(
query
);
final
JSONArray
array2
=
result2
.
optJSONArray
(
Keys
.
RESULTS
);
final
List
<
JSONObject
>
list2
=
CollectionUtils
.<
JSONObject
>
jsonArrayToList
(
array2
);
ret
.
addAll
(
list2
);
}
return
ret
;
}
/**
* Gets the {@link ArticleRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
ArticleRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
ArticleRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
core/src/main/java/org/b3log/solo/repository/impl/CommentRepositoryImpl.java
View file @
4af1a1bb
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.io.Serializable
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.cache.Cache
;
import
org.b3log.latke.repository.AbstractRepository
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.Query
;
import
org.b3log.latke.repository.RepositoryException
;
import
org.b3log.latke.repository.SortDirection
;
import
org.b3log.solo.model.Comment
;
import
org.b3log.solo.repository.CommentRepository
;
import
org.b3log.latke.util.CollectionUtils
;
import
org.b3log.solo.model.Article
;
import
org.b3log.solo.repository.ArticleRepository
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Comment repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.8, Oct 18, 2011
* @since 0.3.1
*/
public
final
class
CommentRepositoryImpl
extends
AbstractRepository
implements
CommentRepository
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
CommentRepositoryImpl
.
class
.
getName
());
/**
* Singleton.
*/
private
static
final
CommentRepositoryImpl
SINGLETON
=
new
CommentRepositoryImpl
(
Comment
.
COMMENT
);
/**
* Article repository.
*/
private
ArticleRepository
articleRepository
=
ArticleRepositoryImpl
.
getInstance
();
/**
* Recent comments query results cache key.
*/
public
static
final
String
RECENT_CMTS_CACHE_KEY
=
"recentCMTs"
;
@Override
public
int
removeComments
(
final
String
onId
)
throws
RepositoryException
{
final
List
<
JSONObject
>
comments
=
getComments
(
onId
,
1
,
Integer
.
MAX_VALUE
);
for
(
final
JSONObject
comment
:
comments
)
{
final
String
commentId
=
comment
.
optString
(
Keys
.
OBJECT_ID
);
remove
(
commentId
);
}
LOGGER
.
log
(
Level
.
FINER
,
"Removed comments[onId={0}, removedCnt={1}]"
,
new
Object
[]{
onId
,
comments
.
size
()});
return
comments
.
size
();
}
@Override
public
List
<
JSONObject
>
getComments
(
final
String
onId
,
final
int
currentPageNum
,
final
int
pageSize
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addSort
(
Keys
.
OBJECT_ID
,
SortDirection
.
DESCENDING
).
addFilter
(
Comment
.
COMMENT_ON_ID
,
FilterOperator
.
EQUAL
,
onId
).
setCurrentPageNum
(
currentPageNum
).
setPageSize
(
pageSize
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
return
CollectionUtils
.
jsonArrayToList
(
array
);
}
@Override
@SuppressWarnings
(
"unchecked"
)
public
List
<
JSONObject
>
getRecentComments
(
final
int
num
)
throws
RepositoryException
{
if
(
isCacheEnabled
())
{
final
Cache
<
String
,
Serializable
>
cache
=
getCache
();
final
Object
ret
=
cache
.
get
(
RECENT_CMTS_CACHE_KEY
);
if
(
null
!=
ret
)
{
return
(
List
<
JSONObject
>)
ret
;
}
}
final
Query
query
=
new
Query
().
addSort
(
Keys
.
OBJECT_ID
,
SortDirection
.
DESCENDING
).
setCurrentPageNum
(
1
).
setPageSize
(
num
).
setPageCount
(
1
);
List
<
JSONObject
>
ret
;
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
ret
=
CollectionUtils
.
jsonArrayToList
(
array
);
// Removes unpublished article related comments
removeForUnpublishedArticles
(
ret
);
if
(
isCacheEnabled
())
{
final
Cache
<
String
,
Serializable
>
cache
=
getCache
();
cache
.
put
(
RECENT_CMTS_CACHE_KEY
,
(
Serializable
)
ret
);
}
return
ret
;
}
/**
* Removes comments of unpublished articles for the specified comments.
*
* @param comments the specified comments
* @throws RepositoryException repository exception
*/
private
void
removeForUnpublishedArticles
(
final
List
<
JSONObject
>
comments
)
throws
RepositoryException
{
LOGGER
.
finer
(
"Removing unpublished articles' comments...."
);
final
Iterator
<
JSONObject
>
iterator
=
comments
.
iterator
();
while
(
iterator
.
hasNext
())
{
final
JSONObject
comment
=
iterator
.
next
();
final
String
commentOnType
=
comment
.
optString
(
Comment
.
COMMENT_ON_TYPE
);
if
(
Article
.
ARTICLE
.
equals
(
commentOnType
))
{
final
String
articleId
=
comment
.
optString
(
Comment
.
COMMENT_ON_ID
);
if
(!
articleRepository
.
isPublished
(
articleId
))
{
iterator
.
remove
();
}
}
}
LOGGER
.
finer
(
"Removed unpublished articles' comments...."
);
}
/**
* Gets the {@link CommentRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
CommentRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
CommentRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.io.Serializable
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.cache.Cache
;
import
org.b3log.latke.repository.*
;
import
org.b3log.solo.model.Comment
;
import
org.b3log.solo.repository.CommentRepository
;
import
org.b3log.latke.util.CollectionUtils
;
import
org.b3log.solo.model.Article
;
import
org.b3log.solo.repository.ArticleRepository
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Comment repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.8, Oct 18, 2011
* @since 0.3.1
*/
public
final
class
CommentRepositoryImpl
extends
AbstractRepository
implements
CommentRepository
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
CommentRepositoryImpl
.
class
.
getName
());
/**
* Singleton.
*/
private
static
final
CommentRepositoryImpl
SINGLETON
=
new
CommentRepositoryImpl
(
Comment
.
COMMENT
);
/**
* Article repository.
*/
private
ArticleRepository
articleRepository
=
ArticleRepositoryImpl
.
getInstance
();
/**
* Recent comments query results cache key.
*/
public
static
final
String
RECENT_CMTS_CACHE_KEY
=
"recentCMTs"
;
@Override
public
int
removeComments
(
final
String
onId
)
throws
RepositoryException
{
final
List
<
JSONObject
>
comments
=
getComments
(
onId
,
1
,
Integer
.
MAX_VALUE
);
for
(
final
JSONObject
comment
:
comments
)
{
final
String
commentId
=
comment
.
optString
(
Keys
.
OBJECT_ID
);
remove
(
commentId
);
}
LOGGER
.
log
(
Level
.
FINER
,
"Removed comments[onId={0}, removedCnt={1}]"
,
new
Object
[]{
onId
,
comments
.
size
()});
return
comments
.
size
();
}
@Override
public
List
<
JSONObject
>
getComments
(
final
String
onId
,
final
int
currentPageNum
,
final
int
pageSize
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addSort
(
Keys
.
OBJECT_ID
,
SortDirection
.
DESCENDING
).
setFilter
(
new
PropertyFilter
(
Comment
.
COMMENT_ON_ID
,
FilterOperator
.
EQUAL
,
onId
)).
setCurrentPageNum
(
currentPageNum
).
setPageSize
(
pageSize
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
return
CollectionUtils
.
jsonArrayToList
(
array
);
}
@Override
@SuppressWarnings
(
"unchecked"
)
public
List
<
JSONObject
>
getRecentComments
(
final
int
num
)
throws
RepositoryException
{
if
(
isCacheEnabled
())
{
final
Cache
<
String
,
Serializable
>
cache
=
getCache
();
final
Object
ret
=
cache
.
get
(
RECENT_CMTS_CACHE_KEY
);
if
(
null
!=
ret
)
{
return
(
List
<
JSONObject
>)
ret
;
}
}
final
Query
query
=
new
Query
().
addSort
(
Keys
.
OBJECT_ID
,
SortDirection
.
DESCENDING
).
setCurrentPageNum
(
1
).
setPageSize
(
num
).
setPageCount
(
1
);
List
<
JSONObject
>
ret
;
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
ret
=
CollectionUtils
.
jsonArrayToList
(
array
);
// Removes unpublished article related comments
removeForUnpublishedArticles
(
ret
);
if
(
isCacheEnabled
())
{
final
Cache
<
String
,
Serializable
>
cache
=
getCache
();
cache
.
put
(
RECENT_CMTS_CACHE_KEY
,
(
Serializable
)
ret
);
}
return
ret
;
}
/**
* Removes comments of unpublished articles for the specified comments.
*
* @param comments the specified comments
* @throws RepositoryException repository exception
*/
private
void
removeForUnpublishedArticles
(
final
List
<
JSONObject
>
comments
)
throws
RepositoryException
{
LOGGER
.
finer
(
"Removing unpublished articles' comments...."
);
final
Iterator
<
JSONObject
>
iterator
=
comments
.
iterator
();
while
(
iterator
.
hasNext
())
{
final
JSONObject
comment
=
iterator
.
next
();
final
String
commentOnType
=
comment
.
optString
(
Comment
.
COMMENT_ON_TYPE
);
if
(
Article
.
ARTICLE
.
equals
(
commentOnType
))
{
final
String
articleId
=
comment
.
optString
(
Comment
.
COMMENT_ON_ID
);
if
(!
articleRepository
.
isPublished
(
articleId
))
{
iterator
.
remove
();
}
}
}
LOGGER
.
finer
(
"Removed unpublished articles' comments...."
);
}
/**
* Gets the {@link CommentRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
CommentRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
CommentRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
core/src/main/java/org/b3log/solo/repository/impl/LinkRepositoryImpl.java
View file @
4af1a1bb
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.util.logging.Logger
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.AbstractRepository
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.Query
;
import
org.b3log.latke.repository.RepositoryException
;
import
org.b3log.latke.repository.SortDirection
;
import
org.b3log.solo.model.Link
;
import
org.b3log.solo.repository.LinkRepository
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Link repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.5, Nov 10, 2011
* @since 0.3.1
*/
public
final
class
LinkRepositoryImpl
extends
AbstractRepository
implements
LinkRepository
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
LinkRepositoryImpl
.
class
.
getName
());
/**
* Singleton.
*/
private
static
final
LinkRepositoryImpl
SINGLETON
=
new
LinkRepositoryImpl
(
Link
.
LINK
);
@Override
public
JSONObject
getByAddress
(
final
String
address
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addFilter
(
Link
.
LINK_ADDRESS
,
FilterOperator
.
EQUAL
,
address
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
int
getMaxOrder
()
throws
RepositoryException
{
final
Query
query
=
new
Query
();
query
.
addSort
(
Link
.
LINK_ORDER
,
SortDirection
.
DESCENDING
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
-
1
;
}
return
array
.
optJSONObject
(
0
).
optInt
(
Link
.
LINK_ORDER
);
}
@Override
public
JSONObject
getByOrder
(
final
int
order
)
throws
RepositoryException
{
final
Query
query
=
new
Query
();
query
.
addFilter
(
Link
.
LINK_ORDER
,
FilterOperator
.
EQUAL
,
order
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
JSONObject
getUpper
(
final
String
id
)
throws
RepositoryException
{
final
JSONObject
link
=
get
(
id
);
if
(
null
==
link
)
{
return
null
;
}
final
Query
query
=
new
Query
();
query
.
addFilter
(
Link
.
LINK_ORDER
,
FilterOperator
.
LESS_THAN
,
link
.
optInt
(
Link
.
LINK_ORDER
)).
addSort
(
Link
.
LINK_ORDER
,
SortDirection
.
DESCENDING
);
query
.
setCurrentPageNum
(
1
);
query
.
setPageSize
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
1
!=
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
JSONObject
getUnder
(
final
String
id
)
throws
RepositoryException
{
final
JSONObject
link
=
get
(
id
);
if
(
null
==
link
)
{
return
null
;
}
final
Query
query
=
new
Query
();
query
.
addFilter
(
Link
.
LINK_ORDER
,
FilterOperator
.
GREATER_THAN
,
link
.
optInt
(
Link
.
LINK_ORDER
)).
addSort
(
Link
.
LINK_ORDER
,
SortDirection
.
ASCENDING
);
query
.
setCurrentPageNum
(
1
);
query
.
setPageSize
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
1
!=
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
/**
* Gets the {@link LinkRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
LinkRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
LinkRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.util.logging.Logger
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.*
;
import
org.b3log.solo.model.Link
;
import
org.b3log.solo.repository.LinkRepository
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Link repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.5, Nov 10, 2011
* @since 0.3.1
*/
public
final
class
LinkRepositoryImpl
extends
AbstractRepository
implements
LinkRepository
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
LinkRepositoryImpl
.
class
.
getName
());
/**
* Singleton.
*/
private
static
final
LinkRepositoryImpl
SINGLETON
=
new
LinkRepositoryImpl
(
Link
.
LINK
);
@Override
public
JSONObject
getByAddress
(
final
String
address
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
setFilter
(
new
PropertyFilter
(
Link
.
LINK_ADDRESS
,
FilterOperator
.
EQUAL
,
address
)).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
int
getMaxOrder
()
throws
RepositoryException
{
final
Query
query
=
new
Query
();
query
.
addSort
(
Link
.
LINK_ORDER
,
SortDirection
.
DESCENDING
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
-
1
;
}
return
array
.
optJSONObject
(
0
).
optInt
(
Link
.
LINK_ORDER
);
}
@Override
public
JSONObject
getByOrder
(
final
int
order
)
throws
RepositoryException
{
final
Query
query
=
new
Query
();
query
.
setFilter
(
new
PropertyFilter
(
Link
.
LINK_ORDER
,
FilterOperator
.
EQUAL
,
order
));
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
JSONObject
getUpper
(
final
String
id
)
throws
RepositoryException
{
final
JSONObject
link
=
get
(
id
);
if
(
null
==
link
)
{
return
null
;
}
final
Query
query
=
new
Query
();
query
.
setFilter
(
new
PropertyFilter
(
Link
.
LINK_ORDER
,
FilterOperator
.
LESS_THAN
,
link
.
optInt
(
Link
.
LINK_ORDER
))).
addSort
(
Link
.
LINK_ORDER
,
SortDirection
.
DESCENDING
);
query
.
setCurrentPageNum
(
1
);
query
.
setPageSize
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
1
!=
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
JSONObject
getUnder
(
final
String
id
)
throws
RepositoryException
{
final
JSONObject
link
=
get
(
id
);
if
(
null
==
link
)
{
return
null
;
}
final
Query
query
=
new
Query
();
query
.
setFilter
(
new
PropertyFilter
(
Link
.
LINK_ORDER
,
FilterOperator
.
GREATER_THAN
,
link
.
optInt
(
Link
.
LINK_ORDER
))).
addSort
(
Link
.
LINK_ORDER
,
SortDirection
.
ASCENDING
);
query
.
setCurrentPageNum
(
1
);
query
.
setPageSize
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
1
!=
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
/**
* Gets the {@link LinkRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
LinkRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
LinkRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
core/src/main/java/org/b3log/solo/repository/impl/PageRepositoryImpl.java
View file @
4af1a1bb
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.util.List
;
import
java.util.logging.Logger
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.
AbstractRepository
;
import
org.b3log.latke.
repository.FilterOperator
;
import
org.b3log.
latke.repository.Query
;
import
org.b3log.
latke.repository.RepositoryException
;
import
org.
b3log.latke.repository.SortDirection
;
import
org.
b3log.latke.util.CollectionUtils
;
import
org.b3log.solo.model.Page
;
import
org.b3log.solo.repository.PageRepository
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
*
Page repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.9, Dec 31, 2011
* @since 0.3.1
*/
public
final
class
PageRepositoryImpl
extends
AbstractRepository
implements
PageRepository
{
/**
*
Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
PageRepositoryImpl
.
class
.
getName
());
/**
* Singleton.
*/
private
static
final
PageRepositoryImpl
SINGLETON
=
new
PageRepositoryImpl
(
Page
.
PAGE
);
@Override
public
JSONObject
getByPermalink
(
final
String
permalink
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addFilter
(
Page
.
PAGE_PERMALINK
,
FilterOperator
.
EQUAL
,
permalink
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
int
getMaxOrder
()
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addSort
(
Page
.
PAGE_ORDER
,
SortDirection
.
DESCENDING
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
-
1
;
}
return
array
.
optJSONObject
(
0
).
optInt
(
Page
.
PAGE_ORDER
);
}
@Override
public
JSONObject
getUpper
(
final
String
id
)
throws
RepositoryException
{
final
JSONObject
page
=
get
(
id
);
if
(
null
==
page
)
{
return
null
;
}
final
Query
query
=
new
Query
().
addFilter
(
Page
.
PAGE_ORDER
,
FilterOperator
.
LESS_THAN
,
page
.
optInt
(
Page
.
PAGE_ORDER
)).
addSort
(
Page
.
PAGE_ORDER
,
SortDirection
.
DESCENDING
).
setCurrentPageNum
(
1
).
setPageSize
(
1
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
1
!=
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
JSONObject
getUnder
(
final
String
id
)
throws
RepositoryException
{
final
JSONObject
page
=
get
(
id
);
if
(
null
==
page
)
{
return
null
;
}
final
Query
query
=
new
Query
().
addFilter
(
Page
.
PAGE_ORDER
,
FilterOperator
.
GREATER_THAN
,
page
.
optInt
(
Page
.
PAGE_ORDER
)).
addSort
(
Page
.
PAGE_ORDER
,
SortDirection
.
ASCENDING
).
setCurrentPageNum
(
1
).
setPage
Size
(
1
).
setPageCount
(
1
);
final
JSON
Object
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
1
!=
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
JSONObject
getByOrder
(
final
int
order
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addFilter
(
Page
.
PAGE_ORDER
,
FilterOperator
.
EQUAL
,
order
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
List
<
JSONObject
>
getPages
()
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addSort
(
Page
.
PAGE_ORDER
,
SortDirection
.
ASCENDING
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
return
CollectionUtils
.
jsonArrayToList
(
result
.
optJSONArray
(
Keys
.
RESULTS
));
}
/**
* Gets the {@link PageRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
PageRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
PageRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.util.List
;
import
java.util.logging.Logger
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.
*
;
import
org.b3log.latke.
util.CollectionUtils
;
import
org.b3log.
solo.model.Page
;
import
org.b3log.
solo.repository.PageRepository
;
import
org.
json.JSONArray
;
import
org.
json.JSONObject
;
/**
* Page repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.9, Dec 31, 2011
*
@since 0.3.1
*
/
public
final
class
PageRepositoryImpl
extends
AbstractRepository
implements
PageRepository
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
PageRepositoryImpl
.
class
.
getName
());
/**
*
Singleton.
*/
private
static
final
PageRepositoryImpl
SINGLETON
=
new
PageRepositoryImpl
(
Page
.
PAGE
);
@Override
public
JSONObject
getByPermalink
(
final
String
permalink
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
setFilter
(
new
PropertyFilter
(
Page
.
PAGE_PERMALINK
,
FilterOperator
.
EQUAL
,
permalink
)).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
int
getMaxOrder
()
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addSort
(
Page
.
PAGE_ORDER
,
SortDirection
.
DESCENDING
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
-
1
;
}
return
array
.
optJSONObject
(
0
).
optInt
(
Page
.
PAGE_ORDER
);
}
@Override
public
JSONObject
getUpper
(
final
String
id
)
throws
RepositoryException
{
final
JSONObject
page
=
get
(
id
);
if
(
null
==
page
)
{
return
null
;
}
final
Query
query
=
new
Query
().
setFilter
(
new
PropertyFilter
(
Page
.
PAGE_ORDER
,
FilterOperator
.
LESS_THAN
,
page
.
optInt
(
Page
.
PAGE_ORDER
))).
addSort
(
Page
.
PAGE_ORDER
,
SortDirection
.
DESCENDING
).
setCurrentPageNum
(
1
).
setPageSize
(
1
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
1
!=
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
JSONObject
getUnder
(
final
String
id
)
throws
RepositoryException
{
final
JSONObject
page
=
get
(
id
);
if
(
null
==
page
)
{
return
null
;
}
final
Query
query
=
new
Query
().
setFilter
(
new
PropertyFilter
(
Page
.
PAGE_ORDER
,
FilterOperator
.
GREATER_THAN
,
page
.
optInt
(
Page
.
PAGE_ORDER
))).
addSort
(
Page
.
PAGE_ORDER
,
SortDirection
.
ASCENDING
).
setCurrentPageNum
(
1
).
setPageSize
(
1
).
setPage
Count
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSON
Array
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
1
!=
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
JSONObject
getByOrder
(
final
int
order
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
setFilter
(
new
PropertyFilter
(
Page
.
PAGE_ORDER
,
FilterOperator
.
EQUAL
,
order
)).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
List
<
JSONObject
>
getPages
()
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addSort
(
Page
.
PAGE_ORDER
,
SortDirection
.
ASCENDING
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
return
CollectionUtils
.
jsonArrayToList
(
result
.
optJSONArray
(
Keys
.
RESULTS
));
}
/**
* Gets the {@link PageRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
PageRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
PageRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
core/src/main/java/org/b3log/solo/repository/impl/TagArticleRepositoryImpl.java
View file @
4af1a1bb
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.util.List
;
import
java.util.logging.Logger
;
import
org.b3log.solo.model.Article
;
import
org.b3log.solo.model.Tag
;
import
org.b3log.solo.repository.TagArticleRepository
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.AbstractRepository
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.Query
;
import
org.b3log.latke.repository.RepositoryException
;
import
org.b3log.latke.repository.SortDirection
;
import
org.b3log.latke.util.CollectionUtils
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Tag-Article relation repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.9, Nov 9, 2011
* @since 0.3.1
*/
public
final
class
TagArticleRepositoryImpl
extends
AbstractRepository
implements
TagArticleRepository
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
TagArticleRepositoryImpl
.
class
.
getName
());
/**
* Singleton.
*/
private
static
final
TagArticleRepositoryImpl
SINGLETON
=
new
TagArticleRepositoryImpl
(
Tag
.
TAG
+
"_"
+
Article
.
ARTICLE
);
@Override
public
List
<
JSONObject
>
getByArticleId
(
final
String
articleId
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addFilter
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
,
FilterOperator
.
EQUAL
,
articleId
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
return
CollectionUtils
.
jsonArrayToList
(
array
);
}
@Override
public
JSONObject
getByTagId
(
final
String
tagId
,
final
int
currentPageNum
,
final
int
pageSize
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addFilter
(
Tag
.
TAG
+
"_"
+
Keys
.
OBJECT_ID
,
FilterOperator
.
EQUAL
,
tagId
).
addSort
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
,
SortDirection
.
DESCENDING
).
setCurrentPageNum
(
currentPageNum
).
setPageSize
(
pageSize
).
setPageCount
(
1
);
return
get
(
query
);
}
/**
* Gets the {@link TagArticleRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
TagArticleRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
TagArticleRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.util.List
;
import
java.util.logging.Logger
;
import
org.b3log.solo.model.Article
;
import
org.b3log.solo.model.Tag
;
import
org.b3log.solo.repository.TagArticleRepository
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.*
;
import
org.b3log.latke.util.CollectionUtils
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Tag-Article relation repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.9, Nov 9, 2011
* @since 0.3.1
*/
public
final
class
TagArticleRepositoryImpl
extends
AbstractRepository
implements
TagArticleRepository
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
TagArticleRepositoryImpl
.
class
.
getName
());
/**
* Singleton.
*/
private
static
final
TagArticleRepositoryImpl
SINGLETON
=
new
TagArticleRepositoryImpl
(
Tag
.
TAG
+
"_"
+
Article
.
ARTICLE
);
@Override
public
List
<
JSONObject
>
getByArticleId
(
final
String
articleId
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
setFilter
(
new
PropertyFilter
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
,
FilterOperator
.
EQUAL
,
articleId
)).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
return
CollectionUtils
.
jsonArrayToList
(
array
);
}
@Override
public
JSONObject
getByTagId
(
final
String
tagId
,
final
int
currentPageNum
,
final
int
pageSize
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
setFilter
(
new
PropertyFilter
(
Tag
.
TAG
+
"_"
+
Keys
.
OBJECT_ID
,
FilterOperator
.
EQUAL
,
tagId
)).
addSort
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
,
SortDirection
.
DESCENDING
).
setCurrentPageNum
(
currentPageNum
).
setPageSize
(
pageSize
).
setPageCount
(
1
);
return
get
(
query
);
}
/**
* Gets the {@link TagArticleRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
TagArticleRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
TagArticleRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
core/src/main/java/org/b3log/solo/repository/impl/TagRepositoryImpl.java
View file @
4af1a1bb
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.logging.Logger
;
import
org.b3log.solo.model.Tag
;
import
org.b3log.solo.repository.TagRepository
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.AbstractRepository
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.Query
;
import
org.b3log.latke.repository.RepositoryException
;
import
org.b3log.latke.repository.SortDirection
;
import
org.b3log.latke.util.CollectionUtils
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Tag repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.1.1, Nov 29, 2011
* @since 0.3.1
*/
public
final
class
TagRepositoryImpl
extends
AbstractRepository
implements
TagRepository
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
TagRepositoryImpl
.
class
.
getName
());
/**
* Singleton.
*/
private
static
final
TagRepositoryImpl
SINGLETON
=
new
TagRepositoryImpl
(
Tag
.
TAG
);
/**
* Tag-Article relation repository.
*/
private
TagArticleRepositoryImpl
tagArticleRepository
=
TagArticleRepositoryImpl
.
getInstance
();
@Override
public
JSONObject
getByTitle
(
final
String
tagTitle
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addFilter
(
Tag
.
TAG_TITLE
,
FilterOperator
.
EQUAL
,
tagTitle
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
List
<
JSONObject
>
getMostUsedTags
(
final
int
num
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addSort
(
Tag
.
TAG_PUBLISHED_REFERENCE_COUNT
,
SortDirection
.
DESCENDING
).
setCurrentPageNum
(
1
).
setPageSize
(
num
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
return
CollectionUtils
.
jsonArrayToList
(
array
);
}
@Override
public
List
<
JSONObject
>
getByArticleId
(
final
String
articleId
)
throws
RepositoryException
{
final
List
<
JSONObject
>
ret
=
new
ArrayList
<
JSONObject
>();
final
List
<
JSONObject
>
tagArticleRelations
=
tagArticleRepository
.
getByArticleId
(
articleId
);
for
(
final
JSONObject
tagArticleRelation
:
tagArticleRelations
)
{
final
String
tagId
=
tagArticleRelation
.
optString
(
Tag
.
TAG
+
"_"
+
Keys
.
OBJECT_ID
);
final
JSONObject
tag
=
get
(
tagId
);
ret
.
add
(
tag
);
}
return
ret
;
}
/**
* Gets the {@link TagRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
TagRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
TagRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.logging.Logger
;
import
org.b3log.solo.model.Tag
;
import
org.b3log.solo.repository.TagRepository
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.*
;
import
org.b3log.latke.util.CollectionUtils
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* Tag repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.1.1, Nov 29, 2011
* @since 0.3.1
*/
public
final
class
TagRepositoryImpl
extends
AbstractRepository
implements
TagRepository
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
TagRepositoryImpl
.
class
.
getName
());
/**
* Singleton.
*/
private
static
final
TagRepositoryImpl
SINGLETON
=
new
TagRepositoryImpl
(
Tag
.
TAG
);
/**
* Tag-Article relation repository.
*/
private
TagArticleRepositoryImpl
tagArticleRepository
=
TagArticleRepositoryImpl
.
getInstance
();
@Override
public
JSONObject
getByTitle
(
final
String
tagTitle
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
setFilter
(
new
PropertyFilter
(
Tag
.
TAG_TITLE
,
FilterOperator
.
EQUAL
,
tagTitle
)).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
List
<
JSONObject
>
getMostUsedTags
(
final
int
num
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addSort
(
Tag
.
TAG_PUBLISHED_REFERENCE_COUNT
,
SortDirection
.
DESCENDING
).
setCurrentPageNum
(
1
).
setPageSize
(
num
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
return
CollectionUtils
.
jsonArrayToList
(
array
);
}
@Override
public
List
<
JSONObject
>
getByArticleId
(
final
String
articleId
)
throws
RepositoryException
{
final
List
<
JSONObject
>
ret
=
new
ArrayList
<
JSONObject
>();
final
List
<
JSONObject
>
tagArticleRelations
=
tagArticleRepository
.
getByArticleId
(
articleId
);
for
(
final
JSONObject
tagArticleRelation
:
tagArticleRelations
)
{
final
String
tagId
=
tagArticleRelation
.
optString
(
Tag
.
TAG
+
"_"
+
Keys
.
OBJECT_ID
);
final
JSONObject
tag
=
get
(
tagId
);
ret
.
add
(
tag
);
}
return
ret
;
}
/**
* Gets the {@link TagRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
TagRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
TagRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
core/src/main/java/org/b3log/solo/repository/impl/UserRepositoryImpl.java
View file @
4af1a1bb
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.util.logging.Logger
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.model.Role
;
import
org.b3log.latke.model.User
;
import
org.b3log.latke.repository.AbstractRepository
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.Query
;
import
org.b3log.latke.repository.RepositoryException
;
import
org.b3log.solo.repository.UserRepository
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* User repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.8, Nov 10, 2011
* @since 0.3.1
*/
public
final
class
UserRepositoryImpl
extends
AbstractRepository
implements
UserRepository
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
UserRepositoryImpl
.
class
.
getName
());
/**
* Singleton.
*/
private
static
final
UserRepositoryImpl
SINGLETON
=
new
UserRepositoryImpl
(
User
.
USER
);
@Override
public
JSONObject
getByEmail
(
final
String
email
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
setPageCount
(
1
);
query
.
addFilter
(
User
.
USER_EMAIL
,
FilterOperator
.
EQUAL
,
email
.
toLowerCase
().
trim
());
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
JSONObject
getAdmin
()
throws
RepositoryException
{
final
Query
query
=
new
Query
().
addFilter
(
User
.
USER_ROLE
,
FilterOperator
.
EQUAL
,
Role
.
ADMIN_ROLE
).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
boolean
isAdminEmail
(
final
String
email
)
throws
RepositoryException
{
final
JSONObject
user
=
getByEmail
(
email
);
if
(
null
==
user
)
{
return
false
;
}
return
Role
.
ADMIN_ROLE
.
equals
(
user
.
optString
(
User
.
USER_ROLE
));
}
/**
* Gets the {@link UserRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
UserRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
UserRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
java.util.logging.Logger
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.model.Role
;
import
org.b3log.latke.model.User
;
import
org.b3log.latke.repository.*
;
import
org.b3log.solo.repository.UserRepository
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* User repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.8, Nov 10, 2011
* @since 0.3.1
*/
public
final
class
UserRepositoryImpl
extends
AbstractRepository
implements
UserRepository
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
UserRepositoryImpl
.
class
.
getName
());
/**
* Singleton.
*/
private
static
final
UserRepositoryImpl
SINGLETON
=
new
UserRepositoryImpl
(
User
.
USER
);
@Override
public
JSONObject
getByEmail
(
final
String
email
)
throws
RepositoryException
{
final
Query
query
=
new
Query
().
setPageCount
(
1
);
query
.
setFilter
(
new
PropertyFilter
(
User
.
USER_EMAIL
,
FilterOperator
.
EQUAL
,
email
.
toLowerCase
().
trim
()));
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
JSONObject
getAdmin
()
throws
RepositoryException
{
final
Query
query
=
new
Query
().
setFilter
(
new
PropertyFilter
(
User
.
USER_ROLE
,
FilterOperator
.
EQUAL
,
Role
.
ADMIN_ROLE
)).
setPageCount
(
1
);
final
JSONObject
result
=
get
(
query
);
final
JSONArray
array
=
result
.
optJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
array
.
length
())
{
return
null
;
}
return
array
.
optJSONObject
(
0
);
}
@Override
public
boolean
isAdminEmail
(
final
String
email
)
throws
RepositoryException
{
final
JSONObject
user
=
getByEmail
(
email
);
if
(
null
==
user
)
{
return
false
;
}
return
Role
.
ADMIN_ROLE
.
equals
(
user
.
optString
(
User
.
USER_ROLE
));
}
/**
* Gets the {@link UserRepositoryImpl} singleton.
*
* @return the singleton
*/
public
static
UserRepositoryImpl
getInstance
()
{
return
SINGLETON
;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private
UserRepositoryImpl
(
final
String
name
)
{
super
(
name
);
}
}
core/src/main/java/org/b3log/solo/service/ArticleQueryService.java
View file @
4af1a1bb
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
service
;
import
org.b3log.solo.repository.ArchiveDateArticleRepository
;
import
org.b3log.solo.repository.impl.ArchiveDateArticleRepositoryImpl
;
import
java.util.Set
;
import
org.b3log.solo.model.Sign
;
import
org.b3log.solo.model.Tag
;
import
java.util.Date
;
import
org.b3log.latke.model.User
;
import
org.b3log.solo.model.Common
;
import
org.b3log.solo.util.Articles
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.SortDirection
;
import
org.b3log.latke.repository.Query
;
import
org.b3log.latke.model.Pagination
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.RepositoryException
;
import
org.b3log.latke.service.ServiceException
;
import
org.b3log.latke.util.CollectionUtils
;
import
org.b3log.latke.util.Paginator
;
import
org.b3log.latke.util.Stopwatchs
;
import
org.b3log.latke.util.Strings
;
import
org.b3log.solo.model.Article
;
import
org.b3log.solo.model.Preference
;
import
org.b3log.solo.repository.ArticleRepository
;
import
org.b3log.solo.repository.TagArticleRepository
;
import
org.b3log.solo.repository.TagRepository
;
import
org.b3log.solo.repository.impl.ArticleRepositoryImpl
;
import
org.b3log.solo.repository.impl.TagArticleRepositoryImpl
;
import
org.b3log.solo.repository.impl.TagRepositoryImpl
;
import
org.b3log.solo.util.Statistics
;
import
org.b3log.solo.util.comparator.Comparators
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
import
static
org
.
b3log
.
solo
.
model
.
Article
.*;
import
org.b3log.solo.util.Markdowns
;
/**
* Article query service.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.1.0, May 10, 2012
* @since 0.3.5
*/
public
final
class
ArticleQueryService
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
ArticleQueryService
.
class
.
getName
());
/**
* Article repository.
*/
private
ArticleRepository
articleRepository
=
ArticleRepositoryImpl
.
getInstance
();
/**
* Preference query service.
*/
private
PreferenceQueryService
preferenceQueryService
=
PreferenceQueryService
.
getInstance
();
/**
* Tag repository.
*/
private
TagRepository
tagRepository
=
TagRepositoryImpl
.
getInstance
();
/**
* Tag-Article repository.
*/
private
TagArticleRepository
tagArticleRepository
=
TagArticleRepositoryImpl
.
getInstance
();
/**
* Archive date-Article repository.
*/
private
ArchiveDateArticleRepository
archiveDateArticleRepository
=
ArchiveDateArticleRepositoryImpl
.
getInstance
();
/**
* Statistic utilities.
*/
private
Statistics
statistics
=
Statistics
.
getInstance
();
/**
* Article utilities.
*/
private
static
Articles
articleUtils
=
Articles
.
getInstance
();
/**
* Gets the recent articles with the specified fetch size.
*
* @param fetchSize the specified fetch size
* @return a list of json object, its size less or equal to the specified
* fetch size
* @throws ServiceException service exception
*/
public
List
<
JSONObject
>
getRecentArticles
(
final
int
fetchSize
)
throws
ServiceException
{
try
{
return
articleRepository
.
getRecentArticles
(
fetchSize
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets recent articles failed"
,
e
);
return
Collections
.
emptyList
();
}
}
/**
* Gets an article by the specified article id.
*
* <p>
* <b>Note</b>: The article content and abstract is raw (no editor type processing).
* </p>
*
* @param articleId the specified article id
* @return for example,
* <pre>
* {
* "article": {
* "oId": "",
* "articleTitle": "",
* "articleAbstract": "",
* "articleContent": "",
* "articlePermalink": "",
* "articleHadBeenPublished": boolean,
* "articleCreateDate": java.util.Date,
* "articleTags": [{
* "oId": "",
* "tagTitle": ""
* }, ....],
* "articleSignId": "",
* "articleViewPwd": "",
* "articleEditorType": "",
* "signs": [{
* "oId": "",
* "signHTML": ""
* }, ....]
* }
* }
* </pre>, returns {@code null} if not found
* @throws ServiceException service exception
*/
public
JSONObject
getArticle
(
final
String
articleId
)
throws
ServiceException
{
try
{
final
JSONObject
ret
=
new
JSONObject
();
final
JSONObject
article
=
articleRepository
.
get
(
articleId
);
if
(
null
==
article
)
{
return
null
;
}
ret
.
put
(
ARTICLE
,
article
);
// Tags
final
JSONArray
tags
=
new
JSONArray
();
final
List
<
JSONObject
>
tagArticleRelations
=
tagArticleRepository
.
getByArticleId
(
articleId
);
for
(
int
i
=
0
;
i
<
tagArticleRelations
.
size
();
i
++)
{
final
JSONObject
tagArticleRelation
=
tagArticleRelations
.
get
(
i
);
final
String
tagId
=
tagArticleRelation
.
getString
(
Tag
.
TAG
+
"_"
+
Keys
.
OBJECT_ID
);
final
JSONObject
tag
=
tagRepository
.
get
(
tagId
);
tags
.
put
(
tag
);
}
article
.
put
(
ARTICLE_TAGS_REF
,
tags
);
// Signs
final
JSONObject
preference
=
preferenceQueryService
.
getPreference
();
article
.
put
(
Sign
.
SIGNS
,
new
JSONArray
(
preference
.
getString
(
Preference
.
SIGNS
)));
// Remove unused properties
article
.
remove
(
ARTICLE_AUTHOR_EMAIL
);
article
.
remove
(
ARTICLE_COMMENT_COUNT
);
article
.
remove
(
ARTICLE_IS_PUBLISHED
);
article
.
remove
(
ARTICLE_PUT_TOP
);
article
.
remove
(
ARTICLE_UPDATE_DATE
);
article
.
remove
(
ARTICLE_VIEW_COUNT
);
article
.
remove
(
ARTICLE_RANDOM_DOUBLE
);
LOGGER
.
log
(
Level
.
FINER
,
"Got an article[id={0}]"
,
articleId
);
return
ret
;
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets an article failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets articles(by crate date descending) by the specified request json
* object.
*
* <p>
* If the property "articleIsPublished" of the specified request json object is {@code true}, the returned articles all are published,
* {@code false} otherwise.
* </p>
*
* <p>
* Specified the "excludes" for results properties exclusion.
* </p>
*
* @param requestJSONObject the specified request json object, for example,
* <pre>
* {
* "paginationCurrentPageNum": 1,
* "paginationPageSize": 20,
* "paginationWindowSize": 10,
* "articleIsPublished": boolean,
* "excludes": ["", ....] // Optional
* }, see {@link Pagination} for more details
* </pre>
* @return for example,
* <pre>
* {
* "pagination": {
* "paginationPageCount": 100,
* "paginationPageNums": [1, 2, 3, 4, 5]
* },
* "articles": [{
* "oId": "",
* "articleTitle": "",
* "articleCommentCount": int,
* "articleCreateTime"; long,
* "articleViewCount": int,
* "articleTags": "tag1, tag2, ....",
* "articlePutTop": boolean,
* "articleSignId": "",
* "articleViewPwd": "",
* "articleEditorType": "",
* .... // Specified by the "excludes"
* }, ....]
* }
* </pre>, order by article update date and sticky(put top).
* @throws ServiceException service exception
* @see Pagination
*/
public
JSONObject
getArticles
(
final
JSONObject
requestJSONObject
)
throws
ServiceException
{
final
JSONObject
ret
=
new
JSONObject
();
try
{
final
int
currentPageNum
=
requestJSONObject
.
getInt
(
Pagination
.
PAGINATION_CURRENT_PAGE_NUM
);
final
int
pageSize
=
requestJSONObject
.
getInt
(
Pagination
.
PAGINATION_PAGE_SIZE
);
final
int
windowSize
=
requestJSONObject
.
getInt
(
Pagination
.
PAGINATION_WINDOW_SIZE
);
final
boolean
articleIsPublished
=
requestJSONObject
.
optBoolean
(
ARTICLE_IS_PUBLISHED
,
true
);
final
Query
query
=
new
Query
().
setCurrentPageNum
(
currentPageNum
).
setPageSize
(
pageSize
).
addSort
(
ARTICLE_PUT_TOP
,
SortDirection
.
DESCENDING
).
addSort
(
ARTICLE_CREATE_DATE
,
SortDirection
.
DESCENDING
).
addFilter
(
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
articleIsPublished
);
int
articleCount
=
statistics
.
getBlogArticleCount
();
if
(!
articleIsPublished
)
{
articleCount
-=
statistics
.
getPublishedBlogArticleCount
();
}
final
int
pageCount
=
(
int
)
Math
.
ceil
((
double
)
articleCount
/
(
double
)
pageSize
);
query
.
setPageCount
(
pageCount
);
final
JSONObject
result
=
articleRepository
.
get
(
query
);
final
JSONObject
pagination
=
new
JSONObject
();
ret
.
put
(
Pagination
.
PAGINATION
,
pagination
);
final
List
<
Integer
>
pageNums
=
Paginator
.
paginate
(
currentPageNum
,
pageSize
,
pageCount
,
windowSize
);
pagination
.
put
(
Pagination
.
PAGINATION_PAGE_COUNT
,
pageCount
);
pagination
.
put
(
Pagination
.
PAGINATION_PAGE_NUMS
,
pageNums
);
final
JSONArray
articles
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
JSONArray
excludes
=
requestJSONObject
.
optJSONArray
(
Keys
.
EXCLUDES
);
excludes
=
null
==
excludes
?
new
JSONArray
()
:
excludes
;
for
(
int
i
=
0
;
i
<
articles
.
length
();
i
++)
{
final
JSONObject
article
=
articles
.
getJSONObject
(
i
);
final
JSONObject
author
=
articleUtils
.
getAuthor
(
article
);
final
String
authorName
=
author
.
getString
(
User
.
USER_NAME
);
article
.
put
(
Common
.
AUTHOR_NAME
,
authorName
);
article
.
put
(
ARTICLE_CREATE_TIME
,
((
Date
)
article
.
get
(
ARTICLE_CREATE_DATE
)).
getTime
());
// Markdown to HTML for content and abstract
markdown
(
article
);
// Remove unused properties
for
(
int
j
=
0
;
j
<
excludes
.
length
();
j
++)
{
article
.
remove
(
excludes
.
optString
(
j
));
}
}
ret
.
put
(
ARTICLES
,
articles
);
return
ret
;
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets a list of published articles with the specified tag id, current page number and page size.
*
* @param tagId the specified tag id
* @param currentPageNum the specified current page number
* @param pageSize the specified page size
* @return a list of articles, returns an empty list if not found
* @throws ServiceException service exception
*/
public
List
<
JSONObject
>
getArticlesByTag
(
final
String
tagId
,
final
int
currentPageNum
,
final
int
pageSize
)
throws
ServiceException
{
try
{
JSONObject
result
=
tagArticleRepository
.
getByTagId
(
tagId
,
currentPageNum
,
pageSize
);
final
JSONArray
tagArticleRelations
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
tagArticleRelations
.
length
())
{
return
Collections
.
emptyList
();
}
final
Set
<
String
>
articleIds
=
new
HashSet
<
String
>();
for
(
int
i
=
0
;
i
<
tagArticleRelations
.
length
();
i
++)
{
final
JSONObject
tagArticleRelation
=
tagArticleRelations
.
getJSONObject
(
i
);
final
String
articleId
=
tagArticleRelation
.
getString
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
);
articleIds
.
add
(
articleId
);
}
final
List
<
JSONObject
>
ret
=
new
ArrayList
<
JSONObject
>();
final
Query
query
=
new
Query
().
addFilter
(
Keys
.
OBJECT_ID
,
FilterOperator
.
IN
,
articleIds
).
setPageCount
(
1
).
index
(
Article
.
ARTICLE_PERMALINK
);
result
=
articleRepository
.
get
(
query
);
final
JSONArray
articles
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
for
(
int
i
=
0
;
i
<
articles
.
length
();
i
++)
{
final
JSONObject
article
=
articles
.
getJSONObject
(
i
);
if
(!
article
.
getBoolean
(
Article
.
ARTICLE_IS_PUBLISHED
))
{
// Skips the unpublished article
continue
;
}
// Markdown to HTML for content and abstract
markdown
(
article
);
ret
.
add
(
article
);
}
return
ret
;
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets articles by tag[id="
+
tagId
+
"] failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets a list of published articles with the specified archive date id, current page number and page size.
*
* @param archiveDateId the specified archive date id
* @param currentPageNum the specified current page number
* @param pageSize the specified page size
* @return a list of articles, returns an empty list if not found
* @throws ServiceException service exception
*/
public
List
<
JSONObject
>
getArticlesByArchiveDate
(
final
String
archiveDateId
,
final
int
currentPageNum
,
final
int
pageSize
)
throws
ServiceException
{
try
{
JSONObject
result
=
archiveDateArticleRepository
.
getByArchiveDateId
(
archiveDateId
,
currentPageNum
,
pageSize
);
final
JSONArray
relations
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
relations
.
length
())
{
return
Collections
.
emptyList
();
}
final
Set
<
String
>
articleIds
=
new
HashSet
<
String
>();
for
(
int
i
=
0
;
i
<
relations
.
length
();
i
++)
{
final
JSONObject
relation
=
relations
.
getJSONObject
(
i
);
final
String
articleId
=
relation
.
getString
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
);
articleIds
.
add
(
articleId
);
}
final
List
<
JSONObject
>
ret
=
new
ArrayList
<
JSONObject
>();
final
Query
query
=
new
Query
().
addFilter
(
Keys
.
OBJECT_ID
,
FilterOperator
.
IN
,
articleIds
).
setPageCount
(
1
).
index
(
Article
.
ARTICLE_PERMALINK
);
result
=
articleRepository
.
get
(
query
);
final
JSONArray
articles
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
for
(
int
i
=
0
;
i
<
articles
.
length
();
i
++)
{
final
JSONObject
article
=
articles
.
getJSONObject
(
i
);
if
(!
article
.
getBoolean
(
Article
.
ARTICLE_IS_PUBLISHED
))
{
// Skips the unpublished article
continue
;
}
// Markdown to HTML for content and abstract
markdown
(
article
);
ret
.
add
(
article
);
}
return
ret
;
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets articles by archive date[id="
+
archiveDateId
+
"] failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets a list of articles randomly with the specified fetch size.
*
* <p>
* <b>Note</b>: The article content and abstract is raw (no editor type processing).
* </p>
*
* @param fetchSize the specified fetch size
* @return a list of json objects, its size less or equal to the specified
* fetch size
* @throws ServiceException service exception
*/
public
List
<
JSONObject
>
getArticlesRandomly
(
final
int
fetchSize
)
throws
ServiceException
{
try
{
final
List
<
JSONObject
>
ret
=
articleRepository
.
getRandomly
(
fetchSize
);
removeUnusedProperties
(
ret
);
return
ret
;
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets articles randomly failed[fetchSize="
+
fetchSize
+
"]"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets the relevant published articles of the specified article.
*
* <p>
* <b>Note</b>: The article content and abstract is raw (no editor type processing).
* </p>
*
* @param article the specified article
* @param preference the specified preference
* @return a list of articles, returns an empty list if not found
* @throws ServiceException service exception
*/
public
List
<
JSONObject
>
getRelevantArticles
(
final
JSONObject
article
,
final
JSONObject
preference
)
throws
ServiceException
{
try
{
final
int
displayCnt
=
preference
.
getInt
(
Preference
.
RELEVANT_ARTICLES_DISPLAY_CNT
);
final
String
[]
tagTitles
=
article
.
getString
(
Article
.
ARTICLE_TAGS_REF
).
split
(
","
);
final
int
maxTagCnt
=
displayCnt
>
tagTitles
.
length
?
tagTitles
.
length
:
displayCnt
;
final
String
articleId
=
article
.
getString
(
Keys
.
OBJECT_ID
);
final
List
<
JSONObject
>
articles
=
new
ArrayList
<
JSONObject
>();
for
(
int
i
=
0
;
i
<
maxTagCnt
;
i
++)
{
// XXX: should average by tag?
final
String
tagTitle
=
tagTitles
[
i
];
final
JSONObject
tag
=
tagRepository
.
getByTitle
(
tagTitle
);
final
String
tagId
=
tag
.
getString
(
Keys
.
OBJECT_ID
);
final
JSONObject
result
=
tagArticleRepository
.
getByTagId
(
tagId
,
1
,
displayCnt
);
final
JSONArray
tagArticleRelations
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
final
int
relationSize
=
displayCnt
<
tagArticleRelations
.
length
()
?
displayCnt
:
tagArticleRelations
.
length
();
for
(
int
j
=
0
;
j
<
relationSize
;
j
++)
{
final
JSONObject
tagArticleRelation
=
tagArticleRelations
.
getJSONObject
(
j
);
final
String
relatedArticleId
=
tagArticleRelation
.
getString
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
);
if
(
articleId
.
equals
(
relatedArticleId
))
{
continue
;
}
final
JSONObject
relevant
=
articleRepository
.
get
(
relatedArticleId
);
if
(!
relevant
.
getBoolean
(
Article
.
ARTICLE_IS_PUBLISHED
))
{
continue
;
}
boolean
existed
=
false
;
for
(
final
JSONObject
relevantArticle
:
articles
)
{
if
(
relevantArticle
.
getString
(
Keys
.
OBJECT_ID
).
equals
(
relevant
.
getString
(
Keys
.
OBJECT_ID
)))
{
existed
=
true
;
}
}
if
(!
existed
)
{
articles
.
add
(
relevant
);
}
}
}
Collections
.
sort
(
articles
,
Comparators
.
ARTICLE_UPDATE_DATE_COMPARATOR
);
removeUnusedProperties
(
articles
);
if
(
displayCnt
>
articles
.
size
())
{
return
articles
;
}
final
List
<
Integer
>
randomIntegers
=
CollectionUtils
.
getRandomIntegers
(
0
,
articles
.
size
()
-
1
,
displayCnt
);
final
List
<
JSONObject
>
ret
=
new
ArrayList
<
JSONObject
>();
for
(
final
int
index
:
randomIntegers
)
{
ret
.
add
(
articles
.
get
(
index
));
}
return
ret
;
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets relevant articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Determines an article specified by the given article id is published.
*
* @param articleId the given article id
* @return {@code true} if it is published
* @throws ServiceException service exception
*/
public
boolean
isArticlePublished
(
final
String
articleId
)
throws
ServiceException
{
try
{
return
articleRepository
.
isPublished
(
articleId
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Determines the article publish status failed[articleId="
+
articleId
+
"]"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets the next article(by create date) by the specified article id.
*
* <p>
* <b>Note</b>: The article content and abstract is raw (no editor type processing).
* </p>
*
* @param articleId the specified article id
* @return the previous article,
* <pre>
* {
* "articleTitle": "",
* "articlePermalink": ""
* }
* </pre>
* returns {@code null} if not found
* @throws ServiceException service exception
*/
public
JSONObject
getNextArticle
(
final
String
articleId
)
throws
ServiceException
{
try
{
return
articleRepository
.
getNextArticle
(
articleId
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets the next article failed[articleId="
+
articleId
+
"]"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets the previous article(by create date) by the specified article id.
*
* <p>
* <b>Note</b>: The article content and abstract is raw (no editor type processing).
* </p>
*
* @param articleId the specified article id
* @return the previous article,
* <pre>
* {
* "articleTitle": "",
* "articlePermalink": ""
* }
* </pre>
* returns {@code null} if not found
* @throws ServiceException service exception
*/
public
JSONObject
getPreviousArticle
(
final
String
articleId
)
throws
ServiceException
{
try
{
return
articleRepository
.
getPreviousArticle
(
articleId
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets the previous article failed[articleId="
+
articleId
+
"]"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets an article by the specified article id.
*
* <p>
* <b>Note</b>: The article content and abstract is raw (no editor type processing).
* </p>
*
* @param articleId the specified article id
* @return an article, returns {@code null} if not found
* @throws ServiceException service exception
*/
public
JSONObject
getArticleById
(
final
String
articleId
)
throws
ServiceException
{
try
{
return
articleRepository
.
get
(
articleId
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets an article[articleId="
+
articleId
+
"] failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets <em>published</em> articles by the specified author email, current page number and page size.
*
* @param authorEmail the specified author email
* @param currentPageNum the specified current page number
* @param pageSize the specified page size
* @return a list of articles, returns an empty list if not found
* @throws ServiceException service exception
*/
public
List
<
JSONObject
>
getArticlesByAuthorEmail
(
final
String
authorEmail
,
final
int
currentPageNum
,
final
int
pageSize
)
throws
ServiceException
{
try
{
final
JSONObject
result
=
articleRepository
.
getByAuthorEmail
(
authorEmail
,
currentPageNum
,
pageSize
);
final
JSONArray
articles
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
final
List
<
JSONObject
>
ret
=
new
ArrayList
<
JSONObject
>();
for
(
int
i
=
0
;
i
<
articles
.
length
();
i
++)
{
final
JSONObject
article
=
articles
.
getJSONObject
(
i
);
// Markdown to HTML for content and abstract
markdown
(
article
);
ret
.
add
(
article
);
}
return
ret
;
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets articles by author email failed[authorEmail="
+
authorEmail
+
", currentPageNum="
+
currentPageNum
+
", pageSize="
+
pageSize
+
"]"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets article contents with the specified article id.
*
* <p>
* Invoking this method dose not effect on article view count.
* </p>
*
* @param articleId the specified article id
* @return article contents, returns {@code null} if not found
* @throws ServiceException service exception
*/
public
String
getArticleContent
(
final
String
articleId
)
throws
ServiceException
{
if
(
Strings
.
isEmptyOrNull
(
articleId
))
{
return
null
;
}
try
{
final
JSONObject
article
=
articleRepository
.
get
(
articleId
);
if
(
null
==
article
)
{
return
null
;
}
// Markdown to HTML for content and abstract
if
(
"CodeMirror-Markdown"
.
equals
(
article
.
optString
(
ARTICLE_EDITOR_TYPE
)))
{
Stopwatchs
.
start
(
"Get Article Content [Markdown]"
);
final
String
content
=
article
.
optString
(
ARTICLE_CONTENT
);
article
.
put
(
ARTICLE_CONTENT
,
Markdowns
.
toHTML
(
content
));
Stopwatchs
.
end
();
}
return
article
.
getString
(
Article
.
ARTICLE_CONTENT
);
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets article content failed[articleId="
+
articleId
+
"]"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Converts the content and abstract for each of the specified articles to HTML if that is saved by Markdown editor.
*
* @param articles the specified articles
* @throws Exception exception
*/
public
void
markdowns
(
final
List
<
JSONObject
>
articles
)
throws
Exception
{
for
(
final
JSONObject
article
:
articles
)
{
markdown
(
article
);
}
}
/**
* Converts the content and abstract for the specified article to HTML if it is saved by Markdown editor.
*
* @param article the specified article
* @throws Exception exception
*/
public
void
markdown
(
final
JSONObject
article
)
throws
Exception
{
if
(
"CodeMirror-Markdown"
.
equals
(
article
.
optString
(
ARTICLE_EDITOR_TYPE
)))
{
Stopwatchs
.
start
(
"Markdown Article[id="
+
article
.
optString
(
Keys
.
OBJECT_ID
)
+
"]"
);
Stopwatchs
.
start
(
"Content"
);
final
String
content
=
article
.
optString
(
ARTICLE_CONTENT
);
article
.
put
(
ARTICLE_CONTENT
,
Markdowns
.
toHTML
(
content
));
Stopwatchs
.
end
();
final
String
abstractContent
=
article
.
optString
(
ARTICLE_ABSTRACT
);
if
(!
Strings
.
isEmptyOrNull
(
abstractContent
))
{
Stopwatchs
.
start
(
"Abstract"
);
article
.
put
(
ARTICLE_ABSTRACT
,
Markdowns
.
toHTML
(
abstractContent
));
Stopwatchs
.
end
();
}
Stopwatchs
.
end
();
}
}
/**
* Removes unused properties of each article in the specified articles.
*
* <p>
* Remains the following properties:
* <ul>
* <li>{@link Article#ARTICLE_TITLE article title}</li>
* <li>{@link Article#ARTICLE_PERMALINK article permalink}</li>
* </ul>
* </p>
*
* <p>
* The batch version of method {@link #removeUnusedProperties(org.json.JSONObject)}.
* </p>
*
* @param articles the specified articles
* @see #removeUnusedProperties(org.json.JSONObject)
*/
public
void
removeUnusedProperties
(
final
List
<
JSONObject
>
articles
)
{
for
(
final
JSONObject
article
:
articles
)
{
removeUnusedProperties
(
article
);
}
}
/**
* Removes unused properties of the specified article.
*
* <p>
* Remains the following properties:
* <ul>
* <li>{@link Article#ARTICLE_TITLE article title}</li>
* <li>{@link Article#ARTICLE_PERMALINK article permalink}</li>
* </ul>
* </p>
*
* @param article the specified article
* @see #removeUnusedProperties(java.util.List)
*/
public
void
removeUnusedProperties
(
final
JSONObject
article
)
{
article
.
remove
(
Keys
.
OBJECT_ID
);
article
.
remove
(
Article
.
ARTICLE_AUTHOR_EMAIL
);
article
.
remove
(
Article
.
ARTICLE_ABSTRACT
);
article
.
remove
(
Article
.
ARTICLE_COMMENT_COUNT
);
article
.
remove
(
Article
.
ARTICLE_CONTENT
);
article
.
remove
(
Article
.
ARTICLE_CREATE_DATE
);
article
.
remove
(
Article
.
ARTICLE_TAGS_REF
);
article
.
remove
(
Article
.
ARTICLE_UPDATE_DATE
);
article
.
remove
(
Article
.
ARTICLE_VIEW_COUNT
);
article
.
remove
(
Article
.
ARTICLE_RANDOM_DOUBLE
);
article
.
remove
(
Article
.
ARTICLE_IS_PUBLISHED
);
article
.
remove
(
Article
.
ARTICLE_PUT_TOP
);
article
.
remove
(
Article
.
ARTICLE_HAD_BEEN_PUBLISHED
);
}
/**
* Gets the {@link ArticleQueryService} singleton.
*
* @return the singleton
*/
public
static
ArticleQueryService
getInstance
()
{
return
SingletonHolder
.
SINGLETON
;
}
/**
* Private constructor.
*/
private
ArticleQueryService
()
{
}
/**
* Singleton holder.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Oct 3, 2011
*/
private
static
final
class
SingletonHolder
{
/**
* Singleton.
*/
private
static
final
ArticleQueryService
SINGLETON
=
new
ArticleQueryService
();
/**
* Private default constructor.
*/
private
SingletonHolder
()
{
}
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
service
;
import
org.b3log.solo.repository.ArchiveDateArticleRepository
;
import
org.b3log.solo.repository.impl.ArchiveDateArticleRepositoryImpl
;
import
java.util.Set
;
import
org.b3log.solo.model.Sign
;
import
org.b3log.solo.model.Tag
;
import
java.util.Date
;
import
org.b3log.latke.model.User
;
import
org.b3log.solo.model.Common
;
import
org.b3log.solo.util.Articles
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.SortDirection
;
import
org.b3log.latke.repository.Query
;
import
org.b3log.latke.model.Pagination
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.*
;
import
org.b3log.latke.service.ServiceException
;
import
org.b3log.latke.util.CollectionUtils
;
import
org.b3log.latke.util.Paginator
;
import
org.b3log.latke.util.Stopwatchs
;
import
org.b3log.latke.util.Strings
;
import
org.b3log.solo.model.Article
;
import
org.b3log.solo.model.Preference
;
import
org.b3log.solo.repository.ArticleRepository
;
import
org.b3log.solo.repository.TagArticleRepository
;
import
org.b3log.solo.repository.TagRepository
;
import
org.b3log.solo.repository.impl.ArticleRepositoryImpl
;
import
org.b3log.solo.repository.impl.TagArticleRepositoryImpl
;
import
org.b3log.solo.repository.impl.TagRepositoryImpl
;
import
org.b3log.solo.util.Statistics
;
import
org.b3log.solo.util.comparator.Comparators
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
import
static
org
.
b3log
.
solo
.
model
.
Article
.*;
import
org.b3log.solo.util.Markdowns
;
/**
* Article query service.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.1.0, May 10, 2012
* @since 0.3.5
*/
public
final
class
ArticleQueryService
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
ArticleQueryService
.
class
.
getName
());
/**
* Article repository.
*/
private
ArticleRepository
articleRepository
=
ArticleRepositoryImpl
.
getInstance
();
/**
* Preference query service.
*/
private
PreferenceQueryService
preferenceQueryService
=
PreferenceQueryService
.
getInstance
();
/**
* Tag repository.
*/
private
TagRepository
tagRepository
=
TagRepositoryImpl
.
getInstance
();
/**
* Tag-Article repository.
*/
private
TagArticleRepository
tagArticleRepository
=
TagArticleRepositoryImpl
.
getInstance
();
/**
* Archive date-Article repository.
*/
private
ArchiveDateArticleRepository
archiveDateArticleRepository
=
ArchiveDateArticleRepositoryImpl
.
getInstance
();
/**
* Statistic utilities.
*/
private
Statistics
statistics
=
Statistics
.
getInstance
();
/**
* Article utilities.
*/
private
static
Articles
articleUtils
=
Articles
.
getInstance
();
/**
* Gets the recent articles with the specified fetch size.
*
* @param fetchSize the specified fetch size
* @return a list of json object, its size less or equal to the specified
* fetch size
* @throws ServiceException service exception
*/
public
List
<
JSONObject
>
getRecentArticles
(
final
int
fetchSize
)
throws
ServiceException
{
try
{
return
articleRepository
.
getRecentArticles
(
fetchSize
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets recent articles failed"
,
e
);
return
Collections
.
emptyList
();
}
}
/**
* Gets an article by the specified article id.
*
* <p>
* <b>Note</b>: The article content and abstract is raw (no editor type processing).
* </p>
*
* @param articleId the specified article id
* @return for example,
* <pre>
* {
* "article": {
* "oId": "",
* "articleTitle": "",
* "articleAbstract": "",
* "articleContent": "",
* "articlePermalink": "",
* "articleHadBeenPublished": boolean,
* "articleCreateDate": java.util.Date,
* "articleTags": [{
* "oId": "",
* "tagTitle": ""
* }, ....],
* "articleSignId": "",
* "articleViewPwd": "",
* "articleEditorType": "",
* "signs": [{
* "oId": "",
* "signHTML": ""
* }, ....]
* }
* }
* </pre>, returns {@code null} if not found
* @throws ServiceException service exception
*/
public
JSONObject
getArticle
(
final
String
articleId
)
throws
ServiceException
{
try
{
final
JSONObject
ret
=
new
JSONObject
();
final
JSONObject
article
=
articleRepository
.
get
(
articleId
);
if
(
null
==
article
)
{
return
null
;
}
ret
.
put
(
ARTICLE
,
article
);
// Tags
final
JSONArray
tags
=
new
JSONArray
();
final
List
<
JSONObject
>
tagArticleRelations
=
tagArticleRepository
.
getByArticleId
(
articleId
);
for
(
int
i
=
0
;
i
<
tagArticleRelations
.
size
();
i
++)
{
final
JSONObject
tagArticleRelation
=
tagArticleRelations
.
get
(
i
);
final
String
tagId
=
tagArticleRelation
.
getString
(
Tag
.
TAG
+
"_"
+
Keys
.
OBJECT_ID
);
final
JSONObject
tag
=
tagRepository
.
get
(
tagId
);
tags
.
put
(
tag
);
}
article
.
put
(
ARTICLE_TAGS_REF
,
tags
);
// Signs
final
JSONObject
preference
=
preferenceQueryService
.
getPreference
();
article
.
put
(
Sign
.
SIGNS
,
new
JSONArray
(
preference
.
getString
(
Preference
.
SIGNS
)));
// Remove unused properties
article
.
remove
(
ARTICLE_AUTHOR_EMAIL
);
article
.
remove
(
ARTICLE_COMMENT_COUNT
);
article
.
remove
(
ARTICLE_IS_PUBLISHED
);
article
.
remove
(
ARTICLE_PUT_TOP
);
article
.
remove
(
ARTICLE_UPDATE_DATE
);
article
.
remove
(
ARTICLE_VIEW_COUNT
);
article
.
remove
(
ARTICLE_RANDOM_DOUBLE
);
LOGGER
.
log
(
Level
.
FINER
,
"Got an article[id={0}]"
,
articleId
);
return
ret
;
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets an article failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets articles(by crate date descending) by the specified request json
* object.
*
* <p>
* If the property "articleIsPublished" of the specified request json object is {@code true}, the returned articles all are published,
* {@code false} otherwise.
* </p>
*
* <p>
* Specified the "excludes" for results properties exclusion.
* </p>
*
* @param requestJSONObject the specified request json object, for example,
* <pre>
* {
* "paginationCurrentPageNum": 1,
* "paginationPageSize": 20,
* "paginationWindowSize": 10,
* "articleIsPublished": boolean,
* "excludes": ["", ....] // Optional
* }, see {@link Pagination} for more details
* </pre>
* @return for example,
* <pre>
* {
* "pagination": {
* "paginationPageCount": 100,
* "paginationPageNums": [1, 2, 3, 4, 5]
* },
* "articles": [{
* "oId": "",
* "articleTitle": "",
* "articleCommentCount": int,
* "articleCreateTime"; long,
* "articleViewCount": int,
* "articleTags": "tag1, tag2, ....",
* "articlePutTop": boolean,
* "articleSignId": "",
* "articleViewPwd": "",
* "articleEditorType": "",
* .... // Specified by the "excludes"
* }, ....]
* }
* </pre>, order by article update date and sticky(put top).
* @throws ServiceException service exception
* @see Pagination
*/
public
JSONObject
getArticles
(
final
JSONObject
requestJSONObject
)
throws
ServiceException
{
final
JSONObject
ret
=
new
JSONObject
();
try
{
final
int
currentPageNum
=
requestJSONObject
.
getInt
(
Pagination
.
PAGINATION_CURRENT_PAGE_NUM
);
final
int
pageSize
=
requestJSONObject
.
getInt
(
Pagination
.
PAGINATION_PAGE_SIZE
);
final
int
windowSize
=
requestJSONObject
.
getInt
(
Pagination
.
PAGINATION_WINDOW_SIZE
);
final
boolean
articleIsPublished
=
requestJSONObject
.
optBoolean
(
ARTICLE_IS_PUBLISHED
,
true
);
final
Query
query
=
new
Query
().
setCurrentPageNum
(
currentPageNum
).
setPageSize
(
pageSize
).
addSort
(
ARTICLE_PUT_TOP
,
SortDirection
.
DESCENDING
).
addSort
(
ARTICLE_CREATE_DATE
,
SortDirection
.
DESCENDING
).
setFilter
(
new
PropertyFilter
(
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
articleIsPublished
));
int
articleCount
=
statistics
.
getBlogArticleCount
();
if
(!
articleIsPublished
)
{
articleCount
-=
statistics
.
getPublishedBlogArticleCount
();
}
final
int
pageCount
=
(
int
)
Math
.
ceil
((
double
)
articleCount
/
(
double
)
pageSize
);
query
.
setPageCount
(
pageCount
);
final
JSONObject
result
=
articleRepository
.
get
(
query
);
final
JSONObject
pagination
=
new
JSONObject
();
ret
.
put
(
Pagination
.
PAGINATION
,
pagination
);
final
List
<
Integer
>
pageNums
=
Paginator
.
paginate
(
currentPageNum
,
pageSize
,
pageCount
,
windowSize
);
pagination
.
put
(
Pagination
.
PAGINATION_PAGE_COUNT
,
pageCount
);
pagination
.
put
(
Pagination
.
PAGINATION_PAGE_NUMS
,
pageNums
);
final
JSONArray
articles
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
JSONArray
excludes
=
requestJSONObject
.
optJSONArray
(
Keys
.
EXCLUDES
);
excludes
=
null
==
excludes
?
new
JSONArray
()
:
excludes
;
for
(
int
i
=
0
;
i
<
articles
.
length
();
i
++)
{
final
JSONObject
article
=
articles
.
getJSONObject
(
i
);
final
JSONObject
author
=
articleUtils
.
getAuthor
(
article
);
final
String
authorName
=
author
.
getString
(
User
.
USER_NAME
);
article
.
put
(
Common
.
AUTHOR_NAME
,
authorName
);
article
.
put
(
ARTICLE_CREATE_TIME
,
((
Date
)
article
.
get
(
ARTICLE_CREATE_DATE
)).
getTime
());
// Markdown to HTML for content and abstract
markdown
(
article
);
// Remove unused properties
for
(
int
j
=
0
;
j
<
excludes
.
length
();
j
++)
{
article
.
remove
(
excludes
.
optString
(
j
));
}
}
ret
.
put
(
ARTICLES
,
articles
);
return
ret
;
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets a list of published articles with the specified tag id, current page number and page size.
*
* @param tagId the specified tag id
* @param currentPageNum the specified current page number
* @param pageSize the specified page size
* @return a list of articles, returns an empty list if not found
* @throws ServiceException service exception
*/
public
List
<
JSONObject
>
getArticlesByTag
(
final
String
tagId
,
final
int
currentPageNum
,
final
int
pageSize
)
throws
ServiceException
{
try
{
JSONObject
result
=
tagArticleRepository
.
getByTagId
(
tagId
,
currentPageNum
,
pageSize
);
final
JSONArray
tagArticleRelations
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
tagArticleRelations
.
length
())
{
return
Collections
.
emptyList
();
}
final
Set
<
String
>
articleIds
=
new
HashSet
<
String
>();
for
(
int
i
=
0
;
i
<
tagArticleRelations
.
length
();
i
++)
{
final
JSONObject
tagArticleRelation
=
tagArticleRelations
.
getJSONObject
(
i
);
final
String
articleId
=
tagArticleRelation
.
getString
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
);
articleIds
.
add
(
articleId
);
}
final
List
<
JSONObject
>
ret
=
new
ArrayList
<
JSONObject
>();
final
Query
query
=
new
Query
().
setFilter
(
new
PropertyFilter
(
Keys
.
OBJECT_ID
,
FilterOperator
.
IN
,
articleIds
)).
setPageCount
(
1
).
index
(
Article
.
ARTICLE_PERMALINK
);
result
=
articleRepository
.
get
(
query
);
final
JSONArray
articles
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
for
(
int
i
=
0
;
i
<
articles
.
length
();
i
++)
{
final
JSONObject
article
=
articles
.
getJSONObject
(
i
);
if
(!
article
.
getBoolean
(
Article
.
ARTICLE_IS_PUBLISHED
))
{
// Skips the unpublished article
continue
;
}
// Markdown to HTML for content and abstract
markdown
(
article
);
ret
.
add
(
article
);
}
return
ret
;
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets articles by tag[id="
+
tagId
+
"] failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets a list of published articles with the specified archive date id, current page number and page size.
*
* @param archiveDateId the specified archive date id
* @param currentPageNum the specified current page number
* @param pageSize the specified page size
* @return a list of articles, returns an empty list if not found
* @throws ServiceException service exception
*/
public
List
<
JSONObject
>
getArticlesByArchiveDate
(
final
String
archiveDateId
,
final
int
currentPageNum
,
final
int
pageSize
)
throws
ServiceException
{
try
{
JSONObject
result
=
archiveDateArticleRepository
.
getByArchiveDateId
(
archiveDateId
,
currentPageNum
,
pageSize
);
final
JSONArray
relations
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
if
(
0
==
relations
.
length
())
{
return
Collections
.
emptyList
();
}
final
Set
<
String
>
articleIds
=
new
HashSet
<
String
>();
for
(
int
i
=
0
;
i
<
relations
.
length
();
i
++)
{
final
JSONObject
relation
=
relations
.
getJSONObject
(
i
);
final
String
articleId
=
relation
.
getString
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
);
articleIds
.
add
(
articleId
);
}
final
List
<
JSONObject
>
ret
=
new
ArrayList
<
JSONObject
>();
final
Query
query
=
new
Query
().
setFilter
(
new
PropertyFilter
(
Keys
.
OBJECT_ID
,
FilterOperator
.
IN
,
articleIds
)).
setPageCount
(
1
).
index
(
Article
.
ARTICLE_PERMALINK
);
result
=
articleRepository
.
get
(
query
);
final
JSONArray
articles
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
for
(
int
i
=
0
;
i
<
articles
.
length
();
i
++)
{
final
JSONObject
article
=
articles
.
getJSONObject
(
i
);
if
(!
article
.
getBoolean
(
Article
.
ARTICLE_IS_PUBLISHED
))
{
// Skips the unpublished article
continue
;
}
// Markdown to HTML for content and abstract
markdown
(
article
);
ret
.
add
(
article
);
}
return
ret
;
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets articles by archive date[id="
+
archiveDateId
+
"] failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets a list of articles randomly with the specified fetch size.
*
* <p>
* <b>Note</b>: The article content and abstract is raw (no editor type processing).
* </p>
*
* @param fetchSize the specified fetch size
* @return a list of json objects, its size less or equal to the specified
* fetch size
* @throws ServiceException service exception
*/
public
List
<
JSONObject
>
getArticlesRandomly
(
final
int
fetchSize
)
throws
ServiceException
{
try
{
final
List
<
JSONObject
>
ret
=
articleRepository
.
getRandomly
(
fetchSize
);
removeUnusedProperties
(
ret
);
return
ret
;
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets articles randomly failed[fetchSize="
+
fetchSize
+
"]"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets the relevant published articles of the specified article.
*
* <p>
* <b>Note</b>: The article content and abstract is raw (no editor type processing).
* </p>
*
* @param article the specified article
* @param preference the specified preference
* @return a list of articles, returns an empty list if not found
* @throws ServiceException service exception
*/
public
List
<
JSONObject
>
getRelevantArticles
(
final
JSONObject
article
,
final
JSONObject
preference
)
throws
ServiceException
{
try
{
final
int
displayCnt
=
preference
.
getInt
(
Preference
.
RELEVANT_ARTICLES_DISPLAY_CNT
);
final
String
[]
tagTitles
=
article
.
getString
(
Article
.
ARTICLE_TAGS_REF
).
split
(
","
);
final
int
maxTagCnt
=
displayCnt
>
tagTitles
.
length
?
tagTitles
.
length
:
displayCnt
;
final
String
articleId
=
article
.
getString
(
Keys
.
OBJECT_ID
);
final
List
<
JSONObject
>
articles
=
new
ArrayList
<
JSONObject
>();
for
(
int
i
=
0
;
i
<
maxTagCnt
;
i
++)
{
// XXX: should average by tag?
final
String
tagTitle
=
tagTitles
[
i
];
final
JSONObject
tag
=
tagRepository
.
getByTitle
(
tagTitle
);
final
String
tagId
=
tag
.
getString
(
Keys
.
OBJECT_ID
);
final
JSONObject
result
=
tagArticleRepository
.
getByTagId
(
tagId
,
1
,
displayCnt
);
final
JSONArray
tagArticleRelations
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
final
int
relationSize
=
displayCnt
<
tagArticleRelations
.
length
()
?
displayCnt
:
tagArticleRelations
.
length
();
for
(
int
j
=
0
;
j
<
relationSize
;
j
++)
{
final
JSONObject
tagArticleRelation
=
tagArticleRelations
.
getJSONObject
(
j
);
final
String
relatedArticleId
=
tagArticleRelation
.
getString
(
Article
.
ARTICLE
+
"_"
+
Keys
.
OBJECT_ID
);
if
(
articleId
.
equals
(
relatedArticleId
))
{
continue
;
}
final
JSONObject
relevant
=
articleRepository
.
get
(
relatedArticleId
);
if
(!
relevant
.
getBoolean
(
Article
.
ARTICLE_IS_PUBLISHED
))
{
continue
;
}
boolean
existed
=
false
;
for
(
final
JSONObject
relevantArticle
:
articles
)
{
if
(
relevantArticle
.
getString
(
Keys
.
OBJECT_ID
).
equals
(
relevant
.
getString
(
Keys
.
OBJECT_ID
)))
{
existed
=
true
;
}
}
if
(!
existed
)
{
articles
.
add
(
relevant
);
}
}
}
Collections
.
sort
(
articles
,
Comparators
.
ARTICLE_UPDATE_DATE_COMPARATOR
);
removeUnusedProperties
(
articles
);
if
(
displayCnt
>
articles
.
size
())
{
return
articles
;
}
final
List
<
Integer
>
randomIntegers
=
CollectionUtils
.
getRandomIntegers
(
0
,
articles
.
size
()
-
1
,
displayCnt
);
final
List
<
JSONObject
>
ret
=
new
ArrayList
<
JSONObject
>();
for
(
final
int
index
:
randomIntegers
)
{
ret
.
add
(
articles
.
get
(
index
));
}
return
ret
;
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets relevant articles failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Determines an article specified by the given article id is published.
*
* @param articleId the given article id
* @return {@code true} if it is published
* @throws ServiceException service exception
*/
public
boolean
isArticlePublished
(
final
String
articleId
)
throws
ServiceException
{
try
{
return
articleRepository
.
isPublished
(
articleId
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Determines the article publish status failed[articleId="
+
articleId
+
"]"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets the next article(by create date) by the specified article id.
*
* <p>
* <b>Note</b>: The article content and abstract is raw (no editor type processing).
* </p>
*
* @param articleId the specified article id
* @return the previous article,
* <pre>
* {
* "articleTitle": "",
* "articlePermalink": ""
* }
* </pre>
* returns {@code null} if not found
* @throws ServiceException service exception
*/
public
JSONObject
getNextArticle
(
final
String
articleId
)
throws
ServiceException
{
try
{
return
articleRepository
.
getNextArticle
(
articleId
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets the next article failed[articleId="
+
articleId
+
"]"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets the previous article(by create date) by the specified article id.
*
* <p>
* <b>Note</b>: The article content and abstract is raw (no editor type processing).
* </p>
*
* @param articleId the specified article id
* @return the previous article,
* <pre>
* {
* "articleTitle": "",
* "articlePermalink": ""
* }
* </pre>
* returns {@code null} if not found
* @throws ServiceException service exception
*/
public
JSONObject
getPreviousArticle
(
final
String
articleId
)
throws
ServiceException
{
try
{
return
articleRepository
.
getPreviousArticle
(
articleId
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets the previous article failed[articleId="
+
articleId
+
"]"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets an article by the specified article id.
*
* <p>
* <b>Note</b>: The article content and abstract is raw (no editor type processing).
* </p>
*
* @param articleId the specified article id
* @return an article, returns {@code null} if not found
* @throws ServiceException service exception
*/
public
JSONObject
getArticleById
(
final
String
articleId
)
throws
ServiceException
{
try
{
return
articleRepository
.
get
(
articleId
);
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets an article[articleId="
+
articleId
+
"] failed"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets <em>published</em> articles by the specified author email, current page number and page size.
*
* @param authorEmail the specified author email
* @param currentPageNum the specified current page number
* @param pageSize the specified page size
* @return a list of articles, returns an empty list if not found
* @throws ServiceException service exception
*/
public
List
<
JSONObject
>
getArticlesByAuthorEmail
(
final
String
authorEmail
,
final
int
currentPageNum
,
final
int
pageSize
)
throws
ServiceException
{
try
{
final
JSONObject
result
=
articleRepository
.
getByAuthorEmail
(
authorEmail
,
currentPageNum
,
pageSize
);
final
JSONArray
articles
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
final
List
<
JSONObject
>
ret
=
new
ArrayList
<
JSONObject
>();
for
(
int
i
=
0
;
i
<
articles
.
length
();
i
++)
{
final
JSONObject
article
=
articles
.
getJSONObject
(
i
);
// Markdown to HTML for content and abstract
markdown
(
article
);
ret
.
add
(
article
);
}
return
ret
;
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets articles by author email failed[authorEmail="
+
authorEmail
+
", currentPageNum="
+
currentPageNum
+
", pageSize="
+
pageSize
+
"]"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Gets article contents with the specified article id.
*
* <p>
* Invoking this method dose not effect on article view count.
* </p>
*
* @param articleId the specified article id
* @return article contents, returns {@code null} if not found
* @throws ServiceException service exception
*/
public
String
getArticleContent
(
final
String
articleId
)
throws
ServiceException
{
if
(
Strings
.
isEmptyOrNull
(
articleId
))
{
return
null
;
}
try
{
final
JSONObject
article
=
articleRepository
.
get
(
articleId
);
if
(
null
==
article
)
{
return
null
;
}
// Markdown to HTML for content and abstract
if
(
"CodeMirror-Markdown"
.
equals
(
article
.
optString
(
ARTICLE_EDITOR_TYPE
)))
{
Stopwatchs
.
start
(
"Get Article Content [Markdown]"
);
final
String
content
=
article
.
optString
(
ARTICLE_CONTENT
);
article
.
put
(
ARTICLE_CONTENT
,
Markdowns
.
toHTML
(
content
));
Stopwatchs
.
end
();
}
return
article
.
getString
(
Article
.
ARTICLE_CONTENT
);
}
catch
(
final
Exception
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets article content failed[articleId="
+
articleId
+
"]"
,
e
);
throw
new
ServiceException
(
e
);
}
}
/**
* Converts the content and abstract for each of the specified articles to HTML if that is saved by Markdown editor.
*
* @param articles the specified articles
* @throws Exception exception
*/
public
void
markdowns
(
final
List
<
JSONObject
>
articles
)
throws
Exception
{
for
(
final
JSONObject
article
:
articles
)
{
markdown
(
article
);
}
}
/**
* Converts the content and abstract for the specified article to HTML if it is saved by Markdown editor.
*
* @param article the specified article
* @throws Exception exception
*/
public
void
markdown
(
final
JSONObject
article
)
throws
Exception
{
if
(
"CodeMirror-Markdown"
.
equals
(
article
.
optString
(
ARTICLE_EDITOR_TYPE
)))
{
Stopwatchs
.
start
(
"Markdown Article[id="
+
article
.
optString
(
Keys
.
OBJECT_ID
)
+
"]"
);
Stopwatchs
.
start
(
"Content"
);
final
String
content
=
article
.
optString
(
ARTICLE_CONTENT
);
article
.
put
(
ARTICLE_CONTENT
,
Markdowns
.
toHTML
(
content
));
Stopwatchs
.
end
();
final
String
abstractContent
=
article
.
optString
(
ARTICLE_ABSTRACT
);
if
(!
Strings
.
isEmptyOrNull
(
abstractContent
))
{
Stopwatchs
.
start
(
"Abstract"
);
article
.
put
(
ARTICLE_ABSTRACT
,
Markdowns
.
toHTML
(
abstractContent
));
Stopwatchs
.
end
();
}
Stopwatchs
.
end
();
}
}
/**
* Removes unused properties of each article in the specified articles.
*
* <p>
* Remains the following properties:
* <ul>
* <li>{@link Article#ARTICLE_TITLE article title}</li>
* <li>{@link Article#ARTICLE_PERMALINK article permalink}</li>
* </ul>
* </p>
*
* <p>
* The batch version of method {@link #removeUnusedProperties(org.json.JSONObject)}.
* </p>
*
* @param articles the specified articles
* @see #removeUnusedProperties(org.json.JSONObject)
*/
public
void
removeUnusedProperties
(
final
List
<
JSONObject
>
articles
)
{
for
(
final
JSONObject
article
:
articles
)
{
removeUnusedProperties
(
article
);
}
}
/**
* Removes unused properties of the specified article.
*
* <p>
* Remains the following properties:
* <ul>
* <li>{@link Article#ARTICLE_TITLE article title}</li>
* <li>{@link Article#ARTICLE_PERMALINK article permalink}</li>
* </ul>
* </p>
*
* @param article the specified article
* @see #removeUnusedProperties(java.util.List)
*/
public
void
removeUnusedProperties
(
final
JSONObject
article
)
{
article
.
remove
(
Keys
.
OBJECT_ID
);
article
.
remove
(
Article
.
ARTICLE_AUTHOR_EMAIL
);
article
.
remove
(
Article
.
ARTICLE_ABSTRACT
);
article
.
remove
(
Article
.
ARTICLE_COMMENT_COUNT
);
article
.
remove
(
Article
.
ARTICLE_CONTENT
);
article
.
remove
(
Article
.
ARTICLE_CREATE_DATE
);
article
.
remove
(
Article
.
ARTICLE_TAGS_REF
);
article
.
remove
(
Article
.
ARTICLE_UPDATE_DATE
);
article
.
remove
(
Article
.
ARTICLE_VIEW_COUNT
);
article
.
remove
(
Article
.
ARTICLE_RANDOM_DOUBLE
);
article
.
remove
(
Article
.
ARTICLE_IS_PUBLISHED
);
article
.
remove
(
Article
.
ARTICLE_PUT_TOP
);
article
.
remove
(
Article
.
ARTICLE_HAD_BEEN_PUBLISHED
);
}
/**
* Gets the {@link ArticleQueryService} singleton.
*
* @return the singleton
*/
public
static
ArticleQueryService
getInstance
()
{
return
SingletonHolder
.
SINGLETON
;
}
/**
* Private constructor.
*/
private
ArticleQueryService
()
{
}
/**
* Singleton holder.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Oct 3, 2011
*/
private
static
final
class
SingletonHolder
{
/**
* Singleton.
*/
private
static
final
ArticleQueryService
SINGLETON
=
new
ArticleQueryService
();
/**
* Private default constructor.
*/
private
SingletonHolder
()
{
}
}
}
core/src/main/java/org/b3log/solo/util/Articles.java
View file @
4af1a1bb
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
util
;
import
java.io.UnsupportedEncodingException
;
import
java.net.URLEncoder
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpSession
;
import
org.b3log.solo.model.Article
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.Query
;
import
org.b3log.latke.repository.RepositoryException
;
import
org.b3log.latke.repository.SortDirection
;
import
org.b3log.latke.service.ServiceException
;
import
org.b3log.latke.user.UserService
;
import
org.b3log.latke.user.UserServiceFactory
;
import
org.b3log.latke.util.CollectionUtils
;
import
org.b3log.latke.util.Strings
;
import
org.b3log.solo.model.Common
;
import
org.b3log.solo.model.Preference
;
import
org.b3log.solo.repository.ArticleRepository
;
import
org.b3log.solo.repository.UserRepository
;
import
org.b3log.solo.repository.impl.ArticleRepositoryImpl
;
import
org.b3log.solo.repository.impl.UserRepositoryImpl
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
/**
* Article utilities.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.2.8, May 6, 2012
* @since 0.3.1
*/
public
final
class
Articles
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
Articles
.
class
.
getName
());
/**
* Article repository.
*/
private
ArticleRepository
articleRepository
=
ArticleRepositoryImpl
.
getInstance
();
/**
* User repository.
*/
private
UserRepository
userRepository
=
UserRepositoryImpl
.
getInstance
();
/**
* User service.
*/
private
UserService
userService
=
UserServiceFactory
.
getUserService
();
/**
* Builds article view password form parameters with the specified article.
*
* @param article the specified article
* @return parameters string, for example,
* <pre>
* "?articleId=xxx&articleTitle=xxx&articlePermalink=xxx&articleAbstract=xxx"
* </pre>
* @throws UnsupportedEncodingException if can not encode the arguments
*/
public
String
buildArticleViewPwdFormParameters
(
final
JSONObject
article
)
throws
UnsupportedEncodingException
{
final
StringBuilder
parametersBuilder
=
new
StringBuilder
(
"?articleId="
).
append
(
article
.
optString
(
Keys
.
OBJECT_ID
)).
append
(
"&articleTitle="
).
append
(
URLEncoder
.
encode
(
article
.
optString
(
Article
.
ARTICLE_TITLE
),
"UTF-8"
)).
append
(
"&articlePermalink="
).
append
(
URLEncoder
.
encode
(
article
.
optString
(
Article
.
ARTICLE_PERMALINK
),
"UTF-8"
)).
append
(
"&articleAbstract="
).
append
(
URLEncoder
.
encode
(
article
.
optString
(
Article
.
ARTICLE_ABSTRACT
,
" "
),
"UTF-8"
));
return
parametersBuilder
.
toString
();
}
/**
* Checks whether need password to view the specified article with the specified request.
*
* <p>
* Checks session, if not represents, checks article property {@link Article#ARTICLE_VIEW_PWD view password}.
* </p>
*
* <p>
* The blogger itself dose not need view password never.
* </p>
*
* @param request the specified request
* @param article the specified article
* @return {@code true} if need, returns {@code false} otherwise
*/
public
boolean
needViewPwd
(
final
HttpServletRequest
request
,
final
JSONObject
article
)
{
final
String
articleViewPwd
=
article
.
optString
(
Article
.
ARTICLE_VIEW_PWD
);
if
(
Strings
.
isEmptyOrNull
(
articleViewPwd
))
{
return
false
;
}
final
HttpSession
session
=
request
.
getSession
(
false
);
if
(
null
!=
session
)
{
@SuppressWarnings
(
"unchecked"
)
Map
<
String
,
String
>
viewPwds
=
(
Map
<
String
,
String
>)
session
.
getAttribute
(
Common
.
ARTICLES_VIEW_PWD
);
if
(
null
==
viewPwds
)
{
viewPwds
=
new
HashMap
<
String
,
String
>();
}
if
(
articleViewPwd
.
equals
(
viewPwds
.
get
(
article
.
optString
(
Keys
.
OBJECT_ID
))))
{
return
false
;
}
}
if
(
null
!=
userService
.
getCurrentUser
(
request
))
{
return
false
;
}
return
true
;
}
/**
* Gets the specified article's author.
*
* <p>
* The specified article has a property
* {@value Article#ARTICLE_AUTHOR_EMAIL}, this method will use this property
* to get a user from users.
* </p>
*
* <p>
* If can't find the specified article's author (i.e. the author has been
* removed by administrator), returns administrator.
* </p>
*
* @param article the specified article
* @return user, {@code null} if not found
* @throws ServiceException service exception
*/
public
JSONObject
getAuthor
(
final
JSONObject
article
)
throws
ServiceException
{
try
{
final
String
email
=
article
.
getString
(
Article
.
ARTICLE_AUTHOR_EMAIL
);
JSONObject
ret
=
userRepository
.
getByEmail
(
email
);
if
(
null
==
ret
)
{
LOGGER
.
log
(
Level
.
WARNING
,
"Gets author of article failed, assumes the administrator is the author of this article[id={0}]"
,
article
.
getString
(
Keys
.
OBJECT_ID
));
// This author may be deleted by admin, use admin as the author
// of this article
ret
=
userRepository
.
getAdmin
();
}
return
ret
;
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets author of article[id={0}] failed"
,
article
.
optString
(
Keys
.
OBJECT_ID
));
throw
new
ServiceException
(
e
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets author of article[id={0}] failed"
,
article
.
optString
(
Keys
.
OBJECT_ID
));
throw
new
ServiceException
(
e
);
}
}
/**
* Article comment count +1 for an article specified by the given article id.
*
* @param articleId the given article id
* @throws JSONException json exception
* @throws RepositoryException repository exception
*/
public
void
incArticleCommentCount
(
final
String
articleId
)
throws
JSONException
,
RepositoryException
{
final
JSONObject
article
=
articleRepository
.
get
(
articleId
);
final
JSONObject
newArticle
=
new
JSONObject
(
article
,
JSONObject
.
getNames
(
article
));
final
int
commentCnt
=
article
.
getInt
(
Article
.
ARTICLE_COMMENT_COUNT
);
newArticle
.
put
(
Article
.
ARTICLE_COMMENT_COUNT
,
commentCnt
+
1
);
articleRepository
.
update
(
articleId
,
newArticle
);
}
/**
* Gets the sign of an article specified by the sign id.
*
* @param signId the specified article id
* @param preference the specified preference
* @return article sign, returns the default sign (which oId is "1") if not found
* @throws RepositoryException repository exception
* @throws JSONException json exception
*/
public
JSONObject
getSign
(
final
String
signId
,
final
JSONObject
preference
)
throws
JSONException
,
RepositoryException
{
final
JSONArray
signs
=
new
JSONArray
(
preference
.
getString
(
Preference
.
SIGNS
));
JSONObject
defaultSign
=
null
;
for
(
int
i
=
0
;
i
<
signs
.
length
();
i
++)
{
final
JSONObject
ret
=
signs
.
getJSONObject
(
i
);
if
(
signId
.
equals
(
ret
.
optString
(
Keys
.
OBJECT_ID
)))
{
return
ret
;
}
if
(
"1"
.
equals
(
ret
.
optString
(
Keys
.
OBJECT_ID
)))
{
defaultSign
=
ret
;
}
}
LOGGER
.
log
(
Level
.
WARNING
,
"Can not find the sign[id={0}], returns a default sign[id=1]"
,
signId
);
if
(
null
==
defaultSign
)
{
throw
new
IllegalStateException
(
"Can not find the default sign which id equals to 1"
);
}
return
defaultSign
;
}
/**
* Determines the specified article has updated.
*
* @param article the specified article
* @return {@code true} if it has updated, {@code false} otherwise
* @throws JSONException json exception
*/
public
boolean
hasUpdated
(
final
JSONObject
article
)
throws
JSONException
{
final
Date
updateDate
=
(
Date
)
article
.
get
(
Article
.
ARTICLE_UPDATE_DATE
);
final
Date
createDate
=
(
Date
)
article
.
get
(
Article
.
ARTICLE_CREATE_DATE
);
return
!
createDate
.
equals
(
updateDate
);
}
/**
* Determines the specified article had been published.
*
* @param article the specified article
* @return {@code true} if it had been published, {@code false} otherwise
* @throws JSONException json exception
*/
public
boolean
hadBeenPublished
(
final
JSONObject
article
)
throws
JSONException
{
return
article
.
getBoolean
(
Article
.
ARTICLE_HAD_BEEN_PUBLISHED
);
}
/**
* Gets all unpublished articles.
*
* @return articles all unpublished articles
* @throws RepositoryException repository exception
* @throws JSONException json exception
*/
public
List
<
JSONObject
>
getUnpublishedArticles
()
throws
RepositoryException
,
JSONException
{
final
Map
<
String
,
SortDirection
>
sorts
=
new
HashMap
<
String
,
SortDirection
>();
sorts
.
put
(
Article
.
ARTICLE_CREATE_DATE
,
SortDirection
.
DESCENDING
);
sorts
.
put
(
Article
.
ARTICLE_PUT_TOP
,
SortDirection
.
DESCENDING
);
final
Query
query
=
new
Query
().
addFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
);
final
JSONObject
result
=
articleRepository
.
get
(
query
);
final
JSONArray
articles
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
return
CollectionUtils
.
jsonArrayToList
(
articles
);
}
/**
* Gets the {@link Articles} singleton.
*
* @return the singleton
*/
public
static
Articles
getInstance
()
{
return
SingletonHolder
.
SINGLETON
;
}
/**
* Private default constructor.
*/
private
Articles
()
{
}
/**
* Singleton holder.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Jan 12, 2011
*/
private
static
final
class
SingletonHolder
{
/**
* Singleton.
*/
private
static
final
Articles
SINGLETON
=
new
Articles
();
/**
* Private default constructor.
*/
private
SingletonHolder
()
{
}
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
util
;
import
java.io.UnsupportedEncodingException
;
import
java.net.URLEncoder
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpSession
;
import
org.b3log.solo.model.Article
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.repository.*
;
import
org.b3log.latke.service.ServiceException
;
import
org.b3log.latke.user.UserService
;
import
org.b3log.latke.user.UserServiceFactory
;
import
org.b3log.latke.util.CollectionUtils
;
import
org.b3log.latke.util.Strings
;
import
org.b3log.solo.model.Common
;
import
org.b3log.solo.model.Preference
;
import
org.b3log.solo.repository.ArticleRepository
;
import
org.b3log.solo.repository.UserRepository
;
import
org.b3log.solo.repository.impl.ArticleRepositoryImpl
;
import
org.b3log.solo.repository.impl.UserRepositoryImpl
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
/**
* Article utilities.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.2.8, May 6, 2012
* @since 0.3.1
*/
public
final
class
Articles
{
/**
* Logger.
*/
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
Articles
.
class
.
getName
());
/**
* Article repository.
*/
private
ArticleRepository
articleRepository
=
ArticleRepositoryImpl
.
getInstance
();
/**
* User repository.
*/
private
UserRepository
userRepository
=
UserRepositoryImpl
.
getInstance
();
/**
* User service.
*/
private
UserService
userService
=
UserServiceFactory
.
getUserService
();
/**
* Builds article view password form parameters with the specified article.
*
* @param article the specified article
* @return parameters string, for example,
* <pre>
* "?articleId=xxx&articleTitle=xxx&articlePermalink=xxx&articleAbstract=xxx"
* </pre>
* @throws UnsupportedEncodingException if can not encode the arguments
*/
public
String
buildArticleViewPwdFormParameters
(
final
JSONObject
article
)
throws
UnsupportedEncodingException
{
final
StringBuilder
parametersBuilder
=
new
StringBuilder
(
"?articleId="
).
append
(
article
.
optString
(
Keys
.
OBJECT_ID
)).
append
(
"&articleTitle="
).
append
(
URLEncoder
.
encode
(
article
.
optString
(
Article
.
ARTICLE_TITLE
),
"UTF-8"
)).
append
(
"&articlePermalink="
).
append
(
URLEncoder
.
encode
(
article
.
optString
(
Article
.
ARTICLE_PERMALINK
),
"UTF-8"
)).
append
(
"&articleAbstract="
).
append
(
URLEncoder
.
encode
(
article
.
optString
(
Article
.
ARTICLE_ABSTRACT
,
" "
),
"UTF-8"
));
return
parametersBuilder
.
toString
();
}
/**
* Checks whether need password to view the specified article with the specified request.
*
* <p>
* Checks session, if not represents, checks article property {@link Article#ARTICLE_VIEW_PWD view password}.
* </p>
*
* <p>
* The blogger itself dose not need view password never.
* </p>
*
* @param request the specified request
* @param article the specified article
* @return {@code true} if need, returns {@code false} otherwise
*/
public
boolean
needViewPwd
(
final
HttpServletRequest
request
,
final
JSONObject
article
)
{
final
String
articleViewPwd
=
article
.
optString
(
Article
.
ARTICLE_VIEW_PWD
);
if
(
Strings
.
isEmptyOrNull
(
articleViewPwd
))
{
return
false
;
}
final
HttpSession
session
=
request
.
getSession
(
false
);
if
(
null
!=
session
)
{
@SuppressWarnings
(
"unchecked"
)
Map
<
String
,
String
>
viewPwds
=
(
Map
<
String
,
String
>)
session
.
getAttribute
(
Common
.
ARTICLES_VIEW_PWD
);
if
(
null
==
viewPwds
)
{
viewPwds
=
new
HashMap
<
String
,
String
>();
}
if
(
articleViewPwd
.
equals
(
viewPwds
.
get
(
article
.
optString
(
Keys
.
OBJECT_ID
))))
{
return
false
;
}
}
if
(
null
!=
userService
.
getCurrentUser
(
request
))
{
return
false
;
}
return
true
;
}
/**
* Gets the specified article's author.
*
* <p>
* The specified article has a property
* {@value Article#ARTICLE_AUTHOR_EMAIL}, this method will use this property
* to get a user from users.
* </p>
*
* <p>
* If can't find the specified article's author (i.e. the author has been
* removed by administrator), returns administrator.
* </p>
*
* @param article the specified article
* @return user, {@code null} if not found
* @throws ServiceException service exception
*/
public
JSONObject
getAuthor
(
final
JSONObject
article
)
throws
ServiceException
{
try
{
final
String
email
=
article
.
getString
(
Article
.
ARTICLE_AUTHOR_EMAIL
);
JSONObject
ret
=
userRepository
.
getByEmail
(
email
);
if
(
null
==
ret
)
{
LOGGER
.
log
(
Level
.
WARNING
,
"Gets author of article failed, assumes the administrator is the author of this article[id={0}]"
,
article
.
getString
(
Keys
.
OBJECT_ID
));
// This author may be deleted by admin, use admin as the author
// of this article
ret
=
userRepository
.
getAdmin
();
}
return
ret
;
}
catch
(
final
RepositoryException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets author of article[id={0}] failed"
,
article
.
optString
(
Keys
.
OBJECT_ID
));
throw
new
ServiceException
(
e
);
}
catch
(
final
JSONException
e
)
{
LOGGER
.
log
(
Level
.
SEVERE
,
"Gets author of article[id={0}] failed"
,
article
.
optString
(
Keys
.
OBJECT_ID
));
throw
new
ServiceException
(
e
);
}
}
/**
* Article comment count +1 for an article specified by the given article id.
*
* @param articleId the given article id
* @throws JSONException json exception
* @throws RepositoryException repository exception
*/
public
void
incArticleCommentCount
(
final
String
articleId
)
throws
JSONException
,
RepositoryException
{
final
JSONObject
article
=
articleRepository
.
get
(
articleId
);
final
JSONObject
newArticle
=
new
JSONObject
(
article
,
JSONObject
.
getNames
(
article
));
final
int
commentCnt
=
article
.
getInt
(
Article
.
ARTICLE_COMMENT_COUNT
);
newArticle
.
put
(
Article
.
ARTICLE_COMMENT_COUNT
,
commentCnt
+
1
);
articleRepository
.
update
(
articleId
,
newArticle
);
}
/**
* Gets the sign of an article specified by the sign id.
*
* @param signId the specified article id
* @param preference the specified preference
* @return article sign, returns the default sign (which oId is "1") if not found
* @throws RepositoryException repository exception
* @throws JSONException json exception
*/
public
JSONObject
getSign
(
final
String
signId
,
final
JSONObject
preference
)
throws
JSONException
,
RepositoryException
{
final
JSONArray
signs
=
new
JSONArray
(
preference
.
getString
(
Preference
.
SIGNS
));
JSONObject
defaultSign
=
null
;
for
(
int
i
=
0
;
i
<
signs
.
length
();
i
++)
{
final
JSONObject
ret
=
signs
.
getJSONObject
(
i
);
if
(
signId
.
equals
(
ret
.
optString
(
Keys
.
OBJECT_ID
)))
{
return
ret
;
}
if
(
"1"
.
equals
(
ret
.
optString
(
Keys
.
OBJECT_ID
)))
{
defaultSign
=
ret
;
}
}
LOGGER
.
log
(
Level
.
WARNING
,
"Can not find the sign[id={0}], returns a default sign[id=1]"
,
signId
);
if
(
null
==
defaultSign
)
{
throw
new
IllegalStateException
(
"Can not find the default sign which id equals to 1"
);
}
return
defaultSign
;
}
/**
* Determines the specified article has updated.
*
* @param article the specified article
* @return {@code true} if it has updated, {@code false} otherwise
* @throws JSONException json exception
*/
public
boolean
hasUpdated
(
final
JSONObject
article
)
throws
JSONException
{
final
Date
updateDate
=
(
Date
)
article
.
get
(
Article
.
ARTICLE_UPDATE_DATE
);
final
Date
createDate
=
(
Date
)
article
.
get
(
Article
.
ARTICLE_CREATE_DATE
);
return
!
createDate
.
equals
(
updateDate
);
}
/**
* Determines the specified article had been published.
*
* @param article the specified article
* @return {@code true} if it had been published, {@code false} otherwise
* @throws JSONException json exception
*/
public
boolean
hadBeenPublished
(
final
JSONObject
article
)
throws
JSONException
{
return
article
.
getBoolean
(
Article
.
ARTICLE_HAD_BEEN_PUBLISHED
);
}
/**
* Gets all unpublished articles.
*
* @return articles all unpublished articles
* @throws RepositoryException repository exception
* @throws JSONException json exception
*/
public
List
<
JSONObject
>
getUnpublishedArticles
()
throws
RepositoryException
,
JSONException
{
final
Map
<
String
,
SortDirection
>
sorts
=
new
HashMap
<
String
,
SortDirection
>();
sorts
.
put
(
Article
.
ARTICLE_CREATE_DATE
,
SortDirection
.
DESCENDING
);
sorts
.
put
(
Article
.
ARTICLE_PUT_TOP
,
SortDirection
.
DESCENDING
);
final
Query
query
=
new
Query
().
setFilter
(
new
PropertyFilter
(
Article
.
ARTICLE_IS_PUBLISHED
,
FilterOperator
.
EQUAL
,
true
));
final
JSONObject
result
=
articleRepository
.
get
(
query
);
final
JSONArray
articles
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
return
CollectionUtils
.
jsonArrayToList
(
articles
);
}
/**
* Gets the {@link Articles} singleton.
*
* @return the singleton
*/
public
static
Articles
getInstance
()
{
return
SingletonHolder
.
SINGLETON
;
}
/**
* Private default constructor.
*/
private
Articles
()
{
}
/**
* Singleton holder.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Jan 12, 2011
*/
private
static
final
class
SingletonHolder
{
/**
* Singleton.
*/
private
static
final
Articles
SINGLETON
=
new
Articles
();
/**
* Private default constructor.
*/
private
SingletonHolder
()
{
}
}
}
core/src/test/java/org/b3log/solo/repository/impl/UserRepositoryImplTestCase.java
View file @
4af1a1bb
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.model.Role
;
import
org.b3log.latke.model.User
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.
Query
;
import
org.b3log.latke.repository.
Transaction
;
import
org.b3log.
solo.AbstractTestCase
;
import
org.b3log.solo.
model.UserExt
;
import
org.b3log.solo.
repository.UserRepository
;
import
org.
json.JSONArray
;
import
org.json.JSON
Object
;
import
org.
testng.Assert
;
import
org.testng.
annotations.Test
;
/**
* {@link UserRepositoryImpl} test case.
*
*
@author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @
version 1.0.0.1, Feb 21, 2012
*
/
@Test
(
suiteName
=
"repository"
)
public
final
class
UserRepositoryImplTestCase
extends
AbstractTestCase
{
/**
* Tests.
*
*
@throws Exception exception
*
/
@Test
public
void
test
()
throws
Exception
{
final
UserRepository
userRepository
=
getUserRepository
();
final
JSONObject
another
=
new
JSONObject
();
another
.
put
(
User
.
USER_NAME
,
"test1"
);
another
.
put
(
User
.
USER_
EMAIL
,
"test1@gmail.com"
);
another
.
put
(
User
.
USER_
PASSWORD
,
"pass1"
);
another
.
put
(
User
.
USER_
ROLE
,
Role
.
DEFAULT_ROLE
);
another
.
put
(
User
Ext
.
USER_ARTICLE_COUNT
,
0
);
another
.
put
(
UserExt
.
USER_
PUBLISHED_ARTICLE_COUNT
,
0
);
Transaction
transaction
=
userRepository
.
beginTransaction
();
userRepository
.
add
(
another
);
transaction
.
commit
();
Assert
.
assertNull
(
userRepository
.
getAdmin
());
JSONObject
admin
=
new
JSONObject
();
admin
.
put
(
User
.
USER_NAME
,
"test"
);
admin
.
put
(
User
.
USER_
EMAIL
,
"test@gmail.com"
);
admin
.
put
(
User
.
USER_
PASSWORD
,
"pass"
);
admin
.
put
(
User
.
USER_
ROLE
,
Role
.
ADMIN_ROLE
);
admin
.
put
(
User
Ext
.
USER_ARTICLE_COUNT
,
0
);
admin
.
put
(
UserExt
.
USER_
PUBLISHED_ARTICLE_COUNT
,
0
);
transaction
=
userRepository
.
beginTransaction
();
userRepository
.
add
(
admin
);
transaction
.
commit
();
Assert
.
assertTrue
(
userRepository
.
isAdminEmail
(
"test@gmail.com"
));
Assert
.
assert
False
(
userRepository
.
isAdminEmail
(
"notFound@gmail.com"
));
admin
=
userRepository
.
getAdmin
();
Assert
.
assertNotNull
(
admin
);
Assert
.
assert
Equals
(
"test"
,
admin
.
optString
(
User
.
USER_NAME
));
final
JSONObject
result
=
userRepository
.
get
(
new
Query
().
addFilter
(
User
.
USER_NAME
,
FilterOperator
.
EQUAL
,
"test1"
));
final
JSONArray
users
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
Assert
.
assertEquals
(
users
.
length
(),
1
);
Assert
.
assertEquals
(
users
.
getJSONObject
(
0
).
getString
(
User
.
USER_EMAIL
),
"test1@gmail.com"
);
final
JSONObject
notFound
=
userRepository
.
getByEmail
(
"not.found@gmail.com"
);
Assert
.
assertNull
(
notFound
);
final
JSONObject
found
=
userRepository
.
getByEmail
(
"test1@gmail.com"
);
Assert
.
assertNotNull
(
found
);
Assert
.
assertEquals
(
found
.
getString
(
User
.
USER_PASSWORD
),
"pass1"
);
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
package
org
.
b3log
.
solo
.
repository
.
impl
;
import
org.b3log.latke.Keys
;
import
org.b3log.latke.model.Role
;
import
org.b3log.latke.model.User
;
import
org.b3log.latke.repository.FilterOperator
;
import
org.b3log.latke.repository.
PropertyFilter
;
import
org.b3log.latke.repository.
Query
;
import
org.b3log.
latke.repository.Transaction
;
import
org.b3log.solo.
AbstractTestCase
;
import
org.b3log.solo.
model.UserExt
;
import
org.
b3log.solo.repository.UserRepository
;
import
org.json.JSON
Array
;
import
org.
json.JSONObject
;
import
org.testng.
Assert
;
import
org.testng.annotations.Test
;
/**
*
{@link UserRepositoryImpl} test case.
*
* @
author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
*
@version 1.0.0.1, Feb 21, 2012
*/
@Test
(
suiteName
=
"repository"
)
public
final
class
UserRepositoryImplTestCase
extends
AbstractTestCase
{
/**
*
Tests.
*
*
@throws Exception exception
*/
@Test
public
void
test
()
throws
Exception
{
final
UserRepository
userRepository
=
getUserRepository
();
final
JSONObject
another
=
new
JSONObject
();
another
.
put
(
User
.
USER_
NAME
,
"test1"
);
another
.
put
(
User
.
USER_
EMAIL
,
"test1@gmail.com"
);
another
.
put
(
User
.
USER_
PASSWORD
,
"pass1"
);
another
.
put
(
User
.
USER_ROLE
,
Role
.
DEFAULT_ROLE
);
another
.
put
(
UserExt
.
USER_
ARTICLE_COUNT
,
0
);
another
.
put
(
UserExt
.
USER_PUBLISHED_ARTICLE_COUNT
,
0
);
Transaction
transaction
=
userRepository
.
beginTransaction
();
userRepository
.
add
(
another
);
transaction
.
commit
();
Assert
.
assertNull
(
userRepository
.
getAdmin
());
JSONObject
admin
=
new
JSONObject
();
admin
.
put
(
User
.
USER_
NAME
,
"test"
);
admin
.
put
(
User
.
USER_
EMAIL
,
"test@gmail.com"
);
admin
.
put
(
User
.
USER_
PASSWORD
,
"pass"
);
admin
.
put
(
User
.
USER_ROLE
,
Role
.
ADMIN_ROLE
);
admin
.
put
(
UserExt
.
USER_
ARTICLE_COUNT
,
0
);
admin
.
put
(
UserExt
.
USER_PUBLISHED_ARTICLE_COUNT
,
0
);
transaction
=
userRepository
.
beginTransaction
();
userRepository
.
add
(
admin
);
transaction
.
commit
();
Assert
.
assert
True
(
userRepository
.
isAdminEmail
(
"test@gmail.com"
));
Assert
.
assertFalse
(
userRepository
.
isAdminEmail
(
"notFound@gmail.com"
));
admin
=
userRepository
.
getAdmin
();
Assert
.
assert
NotNull
(
admin
);
Assert
.
assertEquals
(
"test"
,
admin
.
optString
(
User
.
USER_NAME
));
final
JSONObject
result
=
userRepository
.
get
(
new
Query
().
setFilter
(
new
PropertyFilter
(
User
.
USER_NAME
,
FilterOperator
.
EQUAL
,
"test1"
)));
final
JSONArray
users
=
result
.
getJSONArray
(
Keys
.
RESULTS
);
Assert
.
assertEquals
(
users
.
length
(),
1
);
Assert
.
assertEquals
(
users
.
getJSONObject
(
0
).
getString
(
User
.
USER_EMAIL
),
"test1@gmail.com"
);
final
JSONObject
notFound
=
userRepository
.
getByEmail
(
"not.found@gmail.com"
);
Assert
.
assertNull
(
notFound
);
final
JSONObject
found
=
userRepository
.
getByEmail
(
"test1@gmail.com"
);
Assert
.
assertNotNull
(
found
);
Assert
.
assertEquals
(
found
.
getString
(
User
.
USER_PASSWORD
),
"pass1"
);
}
}
core/src/test/resources/skins/ease/skin.properties
0 → 100644
View file @
4af1a1bb
#
# Copyright (C) 2009, 2010, 2011, B3log Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License 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.
#
#
# Description: ease skin (mock for test).
# Version: 1.0.0.0, Jun 27, 2012
# Author: Liang Ding
#
name
=
ease
version
=
1.0.1
forSolo
=
0.4.6
memo
=
\u
56de
\u
5f52
\u
606c
\u9759
pom.xml
View file @
4af1a1bb
<?xml version="1.0" encoding="UTF-8"?>
<!--
Description: B3log Solo parent POM.
Version: 2.0.2.
0, Jun 19
, 2012
Version: 2.0.2.
1, Jun 27
, 2012
Author: Liang Ding
-->
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
...
...
@@ -32,7 +32,7 @@
<org.b3log.latke.version>
0.5.0-SNAPSHOT
</org.b3log.latke.version>
<org.b3log.latke-gae.version>
0.5.0-SNAPSHOT
</org.b3log.latke-gae.version>
<org.b3log.latke-repository-mysql.version>
0.5.0-SNAPSHOT
</org.b3log.latke-repository-mysql.version>
<gae.version>
1.
6.5
</gae.version>
<gae.version>
1.
7.0
</gae.version>
<freemarker-gae.version>
2.3.19
</freemarker-gae.version>
<jsoup.version>
1.5.2
</jsoup.version>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment