company.gonapps.loghut.dao.PostDao.java Source code

Java tutorial

Introduction

Here is the source code for company.gonapps.loghut.dao.PostDao.java

Source

/**
* LogHut is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LogHut is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LogHut.  If not, see <http://www.gnu.org/licenses/>.
**/

package company.gonapps.loghut.dao;

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import company.gonapps.loghut.comparator.MonthComparator;
import company.gonapps.loghut.comparator.PostDtoComparator;
import company.gonapps.loghut.comparator.YearComparator;
import company.gonapps.loghut.dto.PostDto;
import company.gonapps.loghut.dto.TagDto;
import company.gonapps.loghut.exception.InvalidTagNameException;
import company.gonapps.loghut.utils.FileUtils;

import freemarker.core.ParseException;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateNotFoundException;

@Repository
public class PostDao {

    private static final Pattern postPathStringPattern = Pattern
            .compile("(?<year>\\d\\d\\d\\d)/(?<month>\\d\\d)/(?<day>\\d\\d)_(?<number>\\d+)\\.html(?<secret>s?)$");
    private static final Pattern postYearPattern = Pattern.compile("/(\\d\\d\\d\\d)$");
    private static final Pattern postMonthPattern = Pattern.compile("/(\\d\\d)$");

    private SettingDao settingDao;

    private FreeMarkerConfigurer freeMarkerConfigurer;

    private Template postTemplate;
    private Template mainIndexTemplate;
    private Template yearIndexTemplate;
    private Template monthIndexTemplate;
    private Template postIndexTemplate;

    private ReentrantReadWriteLock rrwl = new ReentrantReadWriteLock();

    private String getPostPathString(PostDto post) {
        return settingDao.getSetting("posts.directory") + post.getLocalPath();
    }

    private String getYearIndexPathString() {
        return settingDao.getSetting("posts.directory") + "/index.html";
    }

    private String getMonthIndexPathString(int year) {
        return settingDao.getSetting("posts.directory") + "/" + String.format("%04d", year) + "/index.html";
    }

    private String getPostIndexPathString(int year, int month) {
        return settingDao.getSetting("posts.directory") + "/" + String.format("%04d", year) + "/"
                + String.format("%02d", month) + "/index.html";
    }

    private String getMainIndexPathString() {
        return settingDao.getSetting("blog.directory") + "/index.html";
    }

    @Autowired
    public void setSettingDao(SettingDao settingDao) {
        this.settingDao = settingDao;
    }

    @Autowired
    public void setFreemarkerConfiguerer(FreeMarkerConfigurer freeMarkerConfigurer) {
        this.freeMarkerConfigurer = freeMarkerConfigurer;
    }

    public void create(PostDto post) throws IOException, TemplateException {
        if (postTemplate == null)
            postTemplate = freeMarkerConfigurer.getConfiguration().getTemplate("blog/post.ftl");

        StringWriter temporaryBuffer = new StringWriter();
        Map<String, Object> modelMap = new HashMap<>();
        modelMap.put("settings", settingDao);
        modelMap.put("post", post);
        postTemplate.process(modelMap, temporaryBuffer);

        Path postPath = Paths.get(getPostPathString(post));
        rrwl.writeLock().lock();
        Files.createDirectories(postPath.getParent());
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(postPath.toFile()))) {
            bufferedWriter.write(temporaryBuffer.toString());
        } finally {
            rrwl.writeLock().unlock();
        }
    }

    public void compress(PostDto post) throws IOException {
        rrwl.writeLock().lock();
        try (BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream(getPostPathString(post) + ".gz"))) {
            FileUtils.compress(getPostPathString(post), bos);
        } finally {
            rrwl.writeLock().unlock();
        }
    }

    public PostDto getPostObject(int year, int month, int day, int number, boolean secretEnabled)
            throws IOException {
        return new PostDto().setYear(year).setMonth(month).setDay(day).setNumber(number)
                .setSecretEnabled(secretEnabled);
    }

    public List<PostDto> getPostObjects() throws IOException {

        rrwl.writeLock().lock();
        List<PostDto> postObjects = new LinkedList<>();
        rrwl.writeLock().unlock();

        rrwl.readLock().lock();
        try {
            for (String postPathString : FileUtils.scan(settingDao.getSetting("posts.directory"))) {
                Matcher matcher = postPathStringPattern.matcher(postPathString);
                if (!matcher.find())
                    continue;
                postObjects.add(getPostObject(new Integer(matcher.group("year")),
                        new Integer(matcher.group("month")), new Integer(matcher.group("day")),
                        new Integer(matcher.group("number")), matcher.group("secret").equals("s")));
            }
        } finally {
            rrwl.readLock().unlock();
        }

        Collections.sort(postObjects, new PostDtoComparator());

        return postObjects;
    }

    public PostDto get(PostDto postObject) throws IOException, InvalidTagNameException {

        PostDto post = getPostObject(postObject.getYear(), postObject.getMonth(), postObject.getDay(),
                postObject.getNumber(), postObject.getSecretEnabled());

        rrwl.readLock().lock();
        Document document;
        try {
            document = Jsoup.parse(new File(getPostPathString(post)), "UTF-8");
        } finally {
            rrwl.readLock().unlock();
        }

        post.setTitle(document.select("#loghut-post-title").first().text());
        post.setText(document.select("#loghut-post-text").first().html());
        List<TagDto> tags = new LinkedList<>();

        for (Element tagElement : document.select(".loghut-post-tag")) {
            tags.add(new TagDto().setName(tagElement.text()));
        }

        post.setTags(tags);
        return post;
    }

    public PostDto get(int year, int month, int day, int number, boolean secretEnabled)
            throws IOException, InvalidTagNameException {
        return get(getPostObject(year, month, day, number, secretEnabled));
    }

    public List<PostDto> getList(int year, int month) throws IOException, InvalidTagNameException {
        List<PostDto> posts = new LinkedList<>();

        rrwl.readLock().lock();
        try (DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get(settingDao.getSetting("posts.directory")
                + "/" + String.format("%04d", year) + "/" + String.format("%02d", month)))) {

            for (Path path : ds) {
                Matcher matcher = postPathStringPattern.matcher(path.toString());
                if (matcher.find())
                    posts.add(get(Integer.parseInt(matcher.group("year")), Integer.parseInt(matcher.group("month")),
                            Integer.parseInt(matcher.group("day")), Integer.parseInt(matcher.group("number")),
                            (matcher.group("secret").equals("s"))));
            }
        } finally {
            rrwl.readLock().unlock();
        }

        Collections.sort(posts, new PostDtoComparator());

        return posts;
    }

    public List<PostDto> getList(List<PostDto> postObjects) throws IOException, InvalidTagNameException {
        List<PostDto> posts = new LinkedList<>();
        rrwl.readLock().lock();
        try {
            for (PostDto postObject : postObjects)
                posts.add(get(postObject));
        } finally {
            rrwl.readLock().unlock();
        }
        return posts;
    }

    public void backup(OutputStream outputStream) throws IOException {
        List<String> filePaths = new LinkedList<>();

        filePaths.add(settingDao.getSetting("blog.directory") + "/index.html");
        filePaths.add(settingDao.getSetting("blog.directory") + "/index.html.gz");
        filePaths.add(settingDao.getSetting("posts.directory"));
        filePaths.add(settingDao.getSetting("tags.directory"));

        rrwl.writeLock().lock();
        try (GzipCompressorOutputStream gcos = new GzipCompressorOutputStream(
                new BufferedOutputStream(outputStream))) {
            FileUtils.archive(filePaths, gcos);
        } finally {
            rrwl.writeLock().unlock();
        }
    }

    public void delete(PostDto post) throws IOException {

        Path postPath = Paths.get(getPostPathString(post));

        rrwl.writeLock().lock();
        try {
            Files.delete(postPath);

            FileUtils.rmdir(postPath.getParent(), new DirectoryStream.Filter<Path>() {
                @Override
                public boolean accept(Path path) throws IOException {
                    return !postPathStringPattern.matcher(path.toString()).find();
                }
            });

            FileUtils.rmdir(postPath.getParent().getParent(), new DirectoryStream.Filter<Path>() {
                @Override
                public boolean accept(Path path) throws IOException {
                    return (!postMonthPattern.matcher(path.toString()).find()) || (!Files.isDirectory(path));
                }
            });
        } finally {
            rrwl.writeLock().unlock();
        }
    }

    public void deleteCompression(PostDto post) throws IOException {
        rrwl.writeLock().lock();
        try {
            Files.delete(Paths.get(getPostPathString(post) + ".gz"));
        } finally {
            rrwl.writeLock().unlock();
        }
    }

    public boolean yearExists(int year) {
        rrwl.readLock().lock();
        boolean exists;
        try {
            exists = Files.exists(
                    Paths.get(settingDao.getSetting("posts.directory") + "/" + String.format("%04d", year)));
        } finally {
            rrwl.readLock().unlock();
        }
        return exists;
    }

    public boolean monthExists(int year, int month) {
        boolean exists;
        rrwl.readLock().lock();
        try {
            exists = Files.exists(Paths.get(settingDao.getSetting("posts.directory") + "/"
                    + String.format("%04d", year) + "/" + String.format("%02d", month)));
        } finally {
            rrwl.readLock().unlock();
        }
        return exists;
    }

    public List<String> getYears() throws IOException {
        List<String> years = new LinkedList<>();

        rrwl.readLock().lock();
        try (DirectoryStream<Path> ds = Files
                .newDirectoryStream(Paths.get(settingDao.getSetting("posts.directory")))) {
            for (Path path : ds) {
                Matcher matcher = postYearPattern.matcher(path.toString());
                if (matcher.find() && Files.isDirectory(path))
                    years.add(matcher.group(1));
            }
        } finally {
            rrwl.readLock().unlock();
        }

        Collections.sort(years, new YearComparator());
        return years;
    }

    public List<String> getMonths(int year) throws IOException {
        List<String> months = new LinkedList<>();

        rrwl.readLock().lock();
        try (DirectoryStream<Path> ds = Files.newDirectoryStream(
                Paths.get(settingDao.getSetting("posts.directory") + "/" + String.format("%04d", year)))) {

            for (Path path : ds) {
                Matcher matcher = postMonthPattern.matcher(path.toString());
                if (matcher.find() && Files.isDirectory(path))
                    months.add(matcher.group(1));
            }
        }
        rrwl.readLock().unlock();

        Collections.sort(months, new MonthComparator());

        return months;
    }

    public void createYearIndex() throws TemplateNotFoundException, IOException, MalformedTemplateNameException,
            ParseException, TemplateException {

        if (yearIndexTemplate == null)
            yearIndexTemplate = freeMarkerConfigurer.getConfiguration().getTemplate("blog/year_index.ftl");

        List<String> years = getYears();
        StringWriter temporaryBuffer = new StringWriter();
        Map<String, Object> modelMap = new HashMap<>();
        modelMap.put("settings", settingDao);
        modelMap.put("years", years);
        yearIndexTemplate.process(modelMap, temporaryBuffer);

        Path yearIndexPath = Paths.get(getYearIndexPathString());
        rrwl.writeLock().lock();
        Files.createDirectories(yearIndexPath.getParent());
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(yearIndexPath.toFile()))) {
            bufferedWriter.write(temporaryBuffer.toString());
        } finally {
            rrwl.writeLock().unlock();
        }
    }

    public void compressYearIndex() throws IOException {
        String yearIndexPathString = getYearIndexPathString();

        rrwl.writeLock().lock();
        try (BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
                new FileOutputStream(yearIndexPathString + ".gz"))) {
            FileUtils.compress(yearIndexPathString, bufferedOutputStream);
        } finally {
            rrwl.writeLock().unlock();
        }
    }

    public void createMonthIndex(int year) throws IOException, TemplateException {

        if (monthIndexTemplate == null)
            monthIndexTemplate = freeMarkerConfigurer.getConfiguration().getTemplate("blog/month_index.ftl");

        List<String> months = getMonths(year);
        StringWriter temporaryBuffer = new StringWriter();
        Map<String, Object> modelMap = new HashMap<>();
        modelMap.put("settings", settingDao);
        modelMap.put("months", months);
        monthIndexTemplate.process(modelMap, temporaryBuffer);

        Path monthIndexPath = Paths.get(getMonthIndexPathString(year));
        rrwl.writeLock().lock();
        Files.createDirectories(monthIndexPath.getParent());
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(monthIndexPath.toFile()))) {
            bufferedWriter.write(temporaryBuffer.toString());
        } finally {
            rrwl.writeLock().unlock();
        }
    }

    public void compressMonthIndex(int year) throws IOException {

        String monthIndexPathString = getMonthIndexPathString(year);
        rrwl.writeLock().lock();
        try (BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
                new FileOutputStream(monthIndexPathString + ".gz"))) {
            FileUtils.compress(monthIndexPathString, bufferedOutputStream);
        } finally {
            rrwl.writeLock().unlock();
        }

    }

    public void createPostIndex(int year, int month)
            throws IOException, TemplateException, InvalidTagNameException {

        if (postIndexTemplate == null)
            postIndexTemplate = freeMarkerConfigurer.getConfiguration().getTemplate("blog/post_index.ftl");

        List<PostDto> posts = getList(year, month);

        StringWriter temporaryBuffer = new StringWriter();
        Map<String, Object> modelMap = new HashMap<>();
        modelMap.put("settings", settingDao);
        modelMap.put("posts", posts);
        postIndexTemplate.process(modelMap, temporaryBuffer);

        Path postIndexPath = Paths.get(getPostIndexPathString(year, month));
        rrwl.writeLock().lock();
        Files.createDirectories(postIndexPath.getParent());
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(postIndexPath.toFile()))) {
            bufferedWriter.write(temporaryBuffer.toString());
        } finally {
            rrwl.writeLock().unlock();
        }
    }

    public void compressPostIndex(int year, int month) throws IOException {

        String postIndexPathString = getPostIndexPathString(year, month);
        rrwl.writeLock().lock();
        try (BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
                new FileOutputStream(postIndexPathString + ".gz"))) {
            FileUtils.compress(postIndexPathString, bufferedOutputStream);
        } finally {
            rrwl.writeLock().unlock();
        }
    }

    public void createMainIndex(PostDto post) throws IOException, TemplateException {

        if (mainIndexTemplate == null)
            mainIndexTemplate = freeMarkerConfigurer.getConfiguration().getTemplate("blog/main_index.ftl");

        StringWriter temporaryBuffer = new StringWriter();
        Map<String, Object> modelMap = new HashMap<>();
        modelMap.put("settings", settingDao);
        modelMap.put("post", post);
        mainIndexTemplate.process(modelMap, temporaryBuffer);

        Path mainIndexPath = Paths.get(getMainIndexPathString());
        rrwl.writeLock().lock();
        Files.createDirectories(mainIndexPath.getParent());
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(mainIndexPath.toFile()))) {
            bufferedWriter.write(temporaryBuffer.toString());
        } finally {
            rrwl.writeLock().unlock();
        }
    }

    public void compressMainIndex() throws IOException {

        String mainIndexPathString = getMainIndexPathString();
        rrwl.writeLock().lock();
        try (BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
                new FileOutputStream(mainIndexPathString + ".gz"))) {
            FileUtils.compress(mainIndexPathString, bufferedOutputStream);
        } finally {
            rrwl.writeLock().unlock();
        }
    }
}