/core/src/main/java/org/b3log/solo/service/PageMgmtService.java

http://github.com/b3log/b3log-solo · Java · 414 lines · 212 code · 61 blank · 141 comment · 30 complexity · c779e5499d650faa41aac974c6121eb0 MD5 · raw file

  1. /*
  2. * Copyright (c) 2009, 2010, 2011, 2012, B3log Team
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.b3log.solo.service;
  17. import java.util.List;
  18. import java.util.logging.Level;
  19. import java.util.logging.Logger;
  20. import org.b3log.latke.Keys;
  21. import org.b3log.latke.repository.RepositoryException;
  22. import org.b3log.latke.repository.Transaction;
  23. import org.b3log.latke.service.LangPropsService;
  24. import org.b3log.latke.service.ServiceException;
  25. import org.b3log.latke.util.Ids;
  26. import org.b3log.latke.util.Strings;
  27. import org.b3log.solo.model.Comment;
  28. import org.b3log.solo.model.Page;
  29. import org.b3log.solo.model.Preference;
  30. import org.b3log.solo.repository.CommentRepository;
  31. import org.b3log.solo.repository.PageRepository;
  32. import org.b3log.solo.repository.impl.CommentRepositoryImpl;
  33. import org.b3log.solo.repository.impl.PageRepositoryImpl;
  34. import org.b3log.solo.util.Comments;
  35. import org.b3log.solo.util.Permalinks;
  36. import org.b3log.solo.util.Statistics;
  37. import org.json.JSONException;
  38. import org.json.JSONObject;
  39. /**
  40. * Page management service.
  41. *
  42. * @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
  43. * @version 1.0.0.7, Jun 8, 2012
  44. * @since 0.4.0
  45. */
  46. public final class PageMgmtService {
  47. /**
  48. * Logger.
  49. */
  50. private static final Logger LOGGER = Logger.getLogger(PageMgmtService.class.getName());
  51. /**
  52. * Page repository.
  53. */
  54. private PageRepository pageRepository = PageRepositoryImpl.getInstance();
  55. /**
  56. * Comment repository.
  57. */
  58. private CommentRepository commentRepository = CommentRepositoryImpl.getInstance();
  59. /**
  60. * Statistic utilities.
  61. */
  62. private Statistics statistics = Statistics.getInstance();
  63. /**
  64. * Language service.
  65. */
  66. private LangPropsService langPropsService = LangPropsService.getInstance();
  67. /**
  68. * Permalink utilities.
  69. */
  70. private Permalinks permalinks = Permalinks.getInstance();
  71. /**
  72. * Preference query service.
  73. */
  74. private PreferenceQueryService preferenceQueryService = PreferenceQueryService.getInstance();
  75. /**
  76. * Updates a page by the specified request json object.
  77. *
  78. * @param requestJSONObject the specified request json object, for example,
  79. * <pre>
  80. * {
  81. * "page": {
  82. * "oId": "",
  83. * "pageTitle": "",
  84. * "pageContent": "",
  85. * "pageOrder": int,
  86. * "pageCommentCount": int,
  87. * "pagePermalink": "",
  88. * "pageCommentable": boolean,
  89. * "pageType": "",
  90. * "pageOpenTarget": ""
  91. * }
  92. * }, see {@link Page} for more details
  93. * </pre>
  94. * @throws ServiceException service exception
  95. */
  96. public void updatePage(final JSONObject requestJSONObject) throws ServiceException {
  97. final Transaction transaction = pageRepository.beginTransaction();
  98. try {
  99. final JSONObject page = requestJSONObject.getJSONObject(Page.PAGE);
  100. final String pageId = page.getString(Keys.OBJECT_ID);
  101. final JSONObject oldPage = pageRepository.get(pageId);
  102. final JSONObject newPage = new JSONObject(page, JSONObject.getNames(page));
  103. newPage.put(Page.PAGE_ORDER, oldPage.getInt(Page.PAGE_ORDER));
  104. newPage.put(Page.PAGE_COMMENT_COUNT, oldPage.getInt(Page.PAGE_COMMENT_COUNT));
  105. String permalink = page.optString(Page.PAGE_PERMALINK).trim();
  106. final String oldPermalink = oldPage.getString(Page.PAGE_PERMALINK);
  107. if (!oldPermalink.equals(permalink)) {
  108. if (Strings.isEmptyOrNull(permalink)) {
  109. permalink = "/pages/" + pageId + ".html";
  110. }
  111. if (Page.PAGE.equals(page.getString(Page.PAGE_TYPE))) {
  112. if (!permalink.startsWith("/")) {
  113. permalink = "/" + permalink;
  114. }
  115. if (Permalinks.invalidPagePermalinkFormat(permalink)) {
  116. if (transaction.isActive()) {
  117. transaction.rollback();
  118. }
  119. throw new ServiceException(langPropsService.get("invalidPermalinkFormatLabel"));
  120. }
  121. if (!oldPermalink.equals(permalink)
  122. && permalinks.exist(permalink)) {
  123. if (transaction.isActive()) {
  124. transaction.rollback();
  125. }
  126. throw new ServiceException(langPropsService.get("duplicatedPermalinkLabel"));
  127. }
  128. }
  129. }
  130. // TODO: SBC case
  131. newPage.put(Page.PAGE_PERMALINK, permalink.replaceAll(" ", "-"));
  132. if (!oldPage.getString(Page.PAGE_PERMALINK).equals(permalink)) { // The permalink has been updated
  133. // Updates related comments' links
  134. processCommentsForPageUpdate(newPage);
  135. }
  136. // Editor type
  137. final JSONObject preference = preferenceQueryService.getPreference();
  138. newPage.put(Page.PAGE_EDITOR_TYPE, preference.optString(Preference.EDITOR_TYPE));
  139. pageRepository.update(pageId, newPage);
  140. transaction.commit();
  141. LOGGER.log(Level.FINER, "Updated a page[id={0}]", pageId);
  142. } catch (final Exception e) {
  143. LOGGER.log(Level.SEVERE, e.getMessage(), e);
  144. if (transaction.isActive()) {
  145. transaction.rollback();
  146. }
  147. throw new ServiceException(e);
  148. }
  149. }
  150. /**
  151. * Removes a page specified by the given page id.
  152. *
  153. * @param pageId the given page id
  154. * @throws ServiceException service exception
  155. */
  156. public void removePage(final String pageId) throws ServiceException {
  157. final Transaction transaction = pageRepository.beginTransaction();
  158. try {
  159. LOGGER.log(Level.FINER, "Removing a page[id={0}]", pageId);
  160. removePageComments(pageId);
  161. pageRepository.remove(pageId);
  162. transaction.commit();
  163. } catch (final Exception e) {
  164. if (transaction.isActive()) {
  165. transaction.rollback();
  166. }
  167. LOGGER.log(Level.SEVERE, "Removes a page[id=" + pageId + "] failed", e);
  168. throw new ServiceException(e);
  169. }
  170. }
  171. /**
  172. * Adds a page with the specified request json object.
  173. *
  174. * @param requestJSONObject the specified request json object, for example,
  175. * <pre>
  176. * {
  177. * "page": {
  178. * "pageTitle": "",
  179. * "pageContent": "",
  180. * "pageOpenTarget": "",
  181. * "pageCommentable": boolean,
  182. * "pageType": "",
  183. * "pagePermalink": "" // optional
  184. * }
  185. * }, see {@link Page} for more details
  186. * </pre>
  187. * @return generated page id
  188. * @throws ServiceException if permalink format checks failed or persists
  189. * failed
  190. */
  191. public String addPage(final JSONObject requestJSONObject) throws ServiceException {
  192. final Transaction transaction = pageRepository.beginTransaction();
  193. try {
  194. final JSONObject page = requestJSONObject.getJSONObject(Page.PAGE);
  195. page.put(Page.PAGE_COMMENT_COUNT, 0);
  196. final int maxOrder = pageRepository.getMaxOrder();
  197. page.put(Page.PAGE_ORDER, maxOrder + 1);
  198. String permalink = page.optString(Page.PAGE_PERMALINK);
  199. if (Strings.isEmptyOrNull(permalink)) {
  200. permalink = "/pages/" + Ids.genTimeMillisId() + ".html";
  201. }
  202. if (Page.PAGE.equals(page.getString(Page.PAGE_TYPE))) {
  203. if (!permalink.startsWith("/")) {
  204. permalink = "/" + permalink;
  205. }
  206. if (Permalinks.invalidPagePermalinkFormat(permalink)) {
  207. if (transaction.isActive()) {
  208. transaction.rollback();
  209. }
  210. throw new ServiceException(langPropsService.get("invalidPermalinkFormatLabel"));
  211. }
  212. if (permalinks.exist(permalink)) {
  213. if (transaction.isActive()) {
  214. transaction.rollback();
  215. }
  216. throw new ServiceException(langPropsService.get("duplicatedPermalinkLabel"));
  217. }
  218. }
  219. // TODO: SBC case
  220. page.put(Page.PAGE_PERMALINK, permalink.replaceAll(" ", "-"));
  221. // Editor type
  222. final JSONObject preference = preferenceQueryService.getPreference();
  223. page.put(Page.PAGE_EDITOR_TYPE, preference.optString(Preference.EDITOR_TYPE));
  224. final String ret = pageRepository.add(page);
  225. transaction.commit();
  226. return ret;
  227. } catch (final JSONException e) {
  228. LOGGER.log(Level.SEVERE, e.getMessage(), e);
  229. if (transaction.isActive()) {
  230. transaction.rollback();
  231. }
  232. throw new ServiceException(e);
  233. } catch (final RepositoryException e) {
  234. LOGGER.log(Level.SEVERE, e.getMessage(), e);
  235. if (transaction.isActive()) {
  236. transaction.rollback();
  237. }
  238. throw new ServiceException(e);
  239. }
  240. }
  241. /**
  242. * Changes the order of a page specified by the given page id with
  243. * the specified direction.
  244. *
  245. * @param pageId the given page id
  246. * @param direction the specified direction, "up"/"down"
  247. * @throws ServiceException service exception
  248. */
  249. public void changeOrder(final String pageId, final String direction) throws ServiceException {
  250. final Transaction transaction = pageRepository.beginTransaction();
  251. try {
  252. final JSONObject srcPage = pageRepository.get(pageId);
  253. final int srcPageOrder = srcPage.getInt(Page.PAGE_ORDER);
  254. JSONObject targetPage = null;
  255. if ("up".equals(direction)) {
  256. targetPage = pageRepository.getUpper(pageId);
  257. } else { // Down
  258. targetPage = pageRepository.getUnder(pageId);
  259. }
  260. if (null == targetPage) {
  261. if (transaction.isActive()) {
  262. transaction.rollback();
  263. }
  264. LOGGER.log(Level.WARNING, "Cant not find the target page of source page[order={0}]", srcPageOrder);
  265. return;
  266. }
  267. // Swaps
  268. srcPage.put(Page.PAGE_ORDER, targetPage.getInt(Page.PAGE_ORDER));
  269. targetPage.put(Page.PAGE_ORDER, srcPageOrder);
  270. pageRepository.update(srcPage.getString(Keys.OBJECT_ID), srcPage);
  271. pageRepository.update(targetPage.getString(Keys.OBJECT_ID), targetPage);
  272. transaction.commit();
  273. } catch (final Exception e) {
  274. if (transaction.isActive()) {
  275. transaction.rollback();
  276. }
  277. LOGGER.log(Level.SEVERE, "Changes page's order failed", e);
  278. throw new ServiceException(e);
  279. }
  280. }
  281. /**
  282. * Gets the {@link PageMgmtService} singleton.
  283. *
  284. * @return the singleton
  285. */
  286. public static PageMgmtService getInstance() {
  287. return SingletonHolder.SINGLETON;
  288. }
  289. /**
  290. * Removes page comments by the specified page id.
  291. *
  292. * <p>
  293. * Removes related comments, sets page/blog comment statistic count.
  294. * </p>
  295. *
  296. * @param pageId the specified page id
  297. * @throws JSONException json exception
  298. * @throws RepositoryException repository exception
  299. */
  300. private void removePageComments(final String pageId) throws JSONException, RepositoryException {
  301. final int removedCnt = commentRepository.removeComments(pageId);
  302. int blogCommentCount = statistics.getBlogCommentCount();
  303. blogCommentCount -= removedCnt;
  304. statistics.setBlogCommentCount(blogCommentCount);
  305. int publishedBlogCommentCount = statistics.getPublishedBlogCommentCount();
  306. publishedBlogCommentCount -= removedCnt;
  307. statistics.setPublishedBlogCommentCount(publishedBlogCommentCount);
  308. }
  309. /**
  310. * Processes comments for page update.
  311. *
  312. * @param page the specified page to update
  313. * @throws Exception exception
  314. */
  315. public void processCommentsForPageUpdate(final JSONObject page) throws Exception {
  316. final String pageId = page.getString(Keys.OBJECT_ID);
  317. final List<JSONObject> comments = commentRepository.getComments(pageId, 1, Integer.MAX_VALUE);
  318. for (final JSONObject comment : comments) {
  319. final String commentId = comment.getString(Keys.OBJECT_ID);
  320. final String sharpURL = Comments.getCommentSharpURLForPage(page, commentId);
  321. comment.put(Comment.COMMENT_SHARP_URL, sharpURL);
  322. if (Strings.isEmptyOrNull(comment.optString(Comment.COMMENT_ORIGINAL_COMMENT_ID))) {
  323. comment.put(Comment.COMMENT_ORIGINAL_COMMENT_ID, "");
  324. }
  325. if (Strings.isEmptyOrNull(comment.optString(Comment.COMMENT_ORIGINAL_COMMENT_NAME))) {
  326. comment.put(Comment.COMMENT_ORIGINAL_COMMENT_NAME, "");
  327. }
  328. commentRepository.update(commentId, comment);
  329. }
  330. }
  331. /**
  332. * Private constructor.
  333. */
  334. private PageMgmtService() {
  335. }
  336. /**
  337. * Singleton holder.
  338. *
  339. * @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
  340. * @version 1.0.0.0, Oct 27, 2011
  341. */
  342. private static final class SingletonHolder {
  343. /**
  344. * Singleton.
  345. */
  346. private static final PageMgmtService SINGLETON = new PageMgmtService();
  347. /**
  348. * Private default constructor.
  349. */
  350. private SingletonHolder() {
  351. }
  352. }
  353. }