PageRenderTime 167ms CodeModel.GetById 39ms app.highlight 80ms RepoModel.GetById 1ms app.codeStats 0ms

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