/******************************************************************************* * Copyright 2013 Ivan Shubin http://mindengine.net * * 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 net.mindengine.blogix.blog.controllers; import java.io.File; import java.io.FileNotFoundException; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import net.mindengine.blogix.config.BlogixConfig; import net.mindengine.blogix.db.EntryFilter; import net.mindengine.blogix.db.EntryList; import net.mindengine.blogix.db.FileDb; import net.mindengine.blogix.model.CategoryAggregation; import net.mindengine.blogix.model.MonthArchive; import net.mindengine.blogix.model.Pagination; import net.mindengine.blogix.model.Post; import net.mindengine.blogix.model.Category; import net.mindengine.blogix.model.YearArchive; import net.mindengine.blogix.utils.BlogixFileUtils; public class Blogix { private static final String ALL_CATEGORIES = "allCategories"; private static final String TITLE = "title"; private static final int DEFAULT_POSTS_PER_PAGE = 10; private static final String CURRENT_PAGE = "currentPage"; private static final String ALL_POSTS_COUNT = "allPostsCount"; private static FileDb<Post> postsDb = createPostsDb(); private static FileDb<Post> docsDb = createDocsDb(); private static FileDb<Category> categoriesDb = createCategoriesDb(); private static String titleBase = loadBaseTitle(); public static Map<String, Object> base() { Map<String, Object> model = loadCommonPostData(); return model; } public static Map<String, Object> homeFirstPage() { Map<String, Object> model = loadCommonPostData(); loadHomePage(model, 1); return model; } public static Map<String, Object> homePage(Integer page) { Map<String, Object> model = loadCommonPostData(); loadHomePage(model, page); return model; } public static Map<String, Object> post(String postId) { Map<String, Object> model = loadCommonPostData(); Post post = postsDb.findById(postId); if (post != null) { model.put("post", post); putTitle(model, post.getTitle()); return model; } else throw new RuntimeException("Cannot find post: " + postId); } public static Map<String, Object> postsByCategory(String categoryId) { return postsByCategoryAndPage(categoryId, 1); } public static Map<String, Object> postsByCategoryAndPage(String categoryId, Integer page) { Map<String, Object> model = loadCommonPostData(); EntryList<Post> allPosts = postsDb.findByFieldContaining("categories", categoryId); int totalPosts = allPosts.size(); model.put("allPostsCount", totalPosts); model.put("posts", allPosts.sortDesc().page(page, DEFAULT_POSTS_PER_PAGE).asJavaList()); model.put("currentPage", page); Category category = categoriesDb.findById(categoryId); model.put("category", category); int totalPages = (int)(totalPosts / DEFAULT_POSTS_PER_PAGE) + 1; model.put("pages", totalPages); model.put("pagination", Pagination.create(1, totalPages, 2, page)); model.put(TITLE, generateTitle(category.getName())); return model; } public static File fileForPost(String postId, String fileName) throws FileNotFoundException { if (postsDb.findAttachments(postId).asJavaList().contains(fileName)) { return postsDb.findAttachmentAsFile(postId, fileName); } throw new FileNotFoundException("There is no '" + fileName + "' attachment for post " + postId); } public static File fileForDocument(String documentId, String fileName) throws FileNotFoundException { if (docsDb.findAttachments(documentId).asJavaList().contains(fileName)) { return docsDb.findAttachmentAsFile(documentId, fileName); } throw new FileNotFoundException("There is no '" + fileName + "' attachment for document " + documentId); } public static Map<String, Object> rssFeedAll() { Map<String, Object> model = new HashMap<String, Object>(); model.put("posts", postsDb.findAll().sortDesc().first(20).asJavaList()); return model; } public static Map<String, Object> rssFeedForCategory(String categoryId) { Map<String, Object> model = new HashMap<String, Object>(); model.put("posts", postsDb.findByFieldContaining("categories", categoryId).sortDesc().first(20).asJavaList()); return model; } public static Map<String, Object> categories() { Map<String, Object> model = loadCommonPostData(); putTitle(model, "Categories"); List<Category> plainCategories = categoriesDb.findAll().asJavaList(); EntryList<Post> allPosts = postsDb.findAll(); List<CategoryAggregation> categories = new LinkedList<CategoryAggregation>(); for (Category category : plainCategories) { CategoryAggregation ca = new CategoryAggregation(); ca.setCategory(category); ca.setRecentPosts(allPosts.sortDesc().filter(onlyRecentPostsForCategory(category.getId())).first(5).asJavaList()); categories.add(ca); } model.put("categories", categories); return model; } private static EntryFilter<Post> onlyRecentPostsForCategory(final String categoryId) { return new EntryFilter<Post>() { @Override public boolean applies(Post post) { String[] categories = post.getCategories(); if (categories != null) { for (String category : categories) { if (category.equals(categoryId)) { return true; } } } return false; } }; } public static Map<String, Object> recentPosts() { return loadCommonPostData(); } public static Map<String, Object> document(String documentId) { Map<String, Object> model = loadCommonPostData(); Post post = docsDb.findById(documentId); if (post != null) { model.put("doc", post); putTitle(model, post.getTitle()); return model; } else throw new RuntimeException("Cannot find document: " + documentId); } public static Map<String, Object> archive() { Map<String, Object> model = loadCommonPostData(); putTitle(model, "Archive"); List<Post> allPosts = postsDb.findAll().sortDesc().asJavaList(); List<YearArchive> archive = new LinkedList<YearArchive>(); if (allPosts.size() > 0) { Collections.sort(allPosts, byDateDescending()); YearArchive currentYear = new YearArchive(yearOfPost(allPosts.get(0))); MonthArchive currentMonth = new MonthArchive(monthOfPost(allPosts.get(0))); currentYear.addMonth(currentMonth); archive.add(currentYear); for (Post post : allPosts) { int postYear = yearOfPost(post); int postMonth = monthOfPost(post); if (currentYear.getYear() != postYear) { currentYear = new YearArchive(postYear); currentMonth = new MonthArchive(postMonth); currentYear.addMonth(currentMonth); archive.add(currentYear); } else { if (currentMonth.getMonth() != postMonth) { currentMonth = new MonthArchive(postMonth); currentYear.addMonth(currentMonth); } } currentMonth.addPost(post); } } model.put("archive", archive); return model; } private static int monthOfPost(Post post) { Calendar calendar = Calendar.getInstance(); calendar.setTime(post.getDate()); return calendar.get(Calendar.MONTH); } private static int yearOfPost(Post post) { Calendar calendar = Calendar.getInstance(); calendar.setTime(post.getDate()); return calendar.get(Calendar.YEAR); } private static Comparator<Post> byDateDescending() { return new Comparator<Post>() { @Override public int compare(Post p1, Post p2) { return (int)(p2.getDate().getTime() / 1000 - p1.getDate().getTime() / 1000); } }; } private static Map<String, Object> loadCommonPostData() { Map<String, Object> model = new HashMap<String, Object>(); model.put("recentPosts", loadRecentPosts()); model.put(ALL_CATEGORIES, getAllCategories()); return model; } private static List<Post> loadRecentPosts() { return postsDb.findAll().sortDesc().first(5).asJavaList(); } private static FileDb<Post> createPostsDb() { return createDb(Post.class, "posts"); } private static FileDb<Category> createCategoriesDb() { return createDb(Category.class, "categories"); } private static FileDb<Post> createDocsDb() { return createDb(Post.class, "docs"); } private static <T extends Comparable<T>> FileDb<T> createDb(Class<T> objectClass, String directoryName) { String filePath = BlogixConfig.getConfig().getBlogixFileDbPath(); if (filePath == null) { throw new IllegalArgumentException("Blogix database is not specified correctly"); } return new FileDb<T>(objectClass, BlogixFileUtils.findFile(filePath + File.separator + directoryName)); } private static void loadHomePage(Map<String, Object> model, int page) { EntryList<Post> allPosts = postsDb.findAll(); int totalPosts = allPosts.size(); model.put(ALL_POSTS_COUNT, totalPosts); List<Post> homePosts = allPosts.sortDesc().page(page, DEFAULT_POSTS_PER_PAGE).asJavaList(); model.put("posts", homePosts); model.put(CURRENT_PAGE, page); int totalPages = (int)(totalPosts / DEFAULT_POSTS_PER_PAGE) + 1; model.put("pages", totalPages); model.put("pagination", Pagination.create(1, totalPages, 2, page)); model.put(TITLE, generateTitle(homeTitle())); } private static Map<String, Category> getAllCategories() { Map<String, Category> map = new HashMap<String, Category>(); List<Category> categoryList = categoriesDb.findAll().asJavaList(); for (Category category : categoryList) { map.put(category.getId(), category); } return map; } private static void putTitle(Map<String, Object> model, String secondaryTitle) { model.put(TITLE, generateTitle(secondaryTitle)); } private static String generateTitle(String secondaryTitle) { if (secondaryTitle == null) { secondaryTitle = ""; } StringBuffer buffer = new StringBuffer(secondaryTitle); if (titleBase != null) { buffer.append(" | "); buffer.append(titleBase); } return buffer.toString(); } private static String homeTitle() { return titleFromConfig("blogix.title.home"); } private static String loadBaseTitle() { return titleFromConfig("blogix.title.base"); } private static String titleFromConfig(String propertyName) { String title = BlogixConfig.getConfig().getProperty(propertyName, null); if (title != null) { title = title.trim(); if (title != null) { return title; } } return null; } }