org.tightblog.service.ThemeManager.java Source code

Java tutorial

Introduction

Here is the source code for org.tightblog.service.ThemeManager.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  The ASF licenses this file to You
 * 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.  For additional information regarding
 * copyright in this work, please see the NOTICE file in the top level
 * directory of this distribution.
 *
 * Source file modified from the original ASF source; all changes made
 * are also under Apache License.
 */
package org.tightblog.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.tightblog.domain.SharedTemplate;
import org.tightblog.domain.SharedTheme;
import org.tightblog.domain.Template;
import org.tightblog.domain.Template.Role;
import org.tightblog.domain.Weblog;
import org.tightblog.domain.WeblogTemplate;
import org.tightblog.domain.WeblogTheme;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.ServletContextAware;
import org.tightblog.repository.WeblogTemplateRepository;

import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;
import javax.annotation.PostConstruct;
import javax.servlet.ServletContext;
import java.io.IOException;
import java.io.InputStream;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Manager interface for accessing Theme related objects.
 */
@Component
public class ThemeManager implements ServletContextAware {

    private static Logger log = LoggerFactory.getLogger(ThemeManager.class);

    private ServletContext servletContext;
    private ObjectMapper objectMapper;
    private WeblogTemplateRepository weblogTemplateRepository;

    @Autowired
    public ThemeManager(ObjectMapper objectMapper, WeblogTemplateRepository weblogTemplateRepository) {
        this.objectMapper = objectMapper;
        this.weblogTemplateRepository = weblogTemplateRepository;
    }

    static {
        // TODO: figure out why PNG is missing from Java MIME types
        FileTypeMap map = FileTypeMap.getDefaultFileTypeMap();
        if (map instanceof MimetypesFileTypeMap) {
            try {
                ((MimetypesFileTypeMap) map).addMimeTypes("image/png png PNG");
            } catch (Exception ignored) {
            }
        }
    }

    // map of themes in format (theme id, Theme)
    private Map<String, SharedTheme> themeMap = new HashMap<>();

    // list of themes
    private List<SharedTheme> themeList = new ArrayList<>();

    @Override
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    @PostConstruct
    public void initialize() {
        String blogThemePath = "/blogthemes";

        Set<String> paths = servletContext.getResourcePaths(blogThemePath);

        if (paths != null && paths.size() > 0) {
            log.info("{} shared blog themes detected, loading...", paths.size());
            for (String path : paths) {
                try {
                    SharedTheme theme = loadThemeData(path);
                    themeMap.put(theme.getId(), theme);
                } catch (Exception unexpected) {
                    // shouldn't happen, so let's learn why it did
                    log.error("Exception processing theme {}, will be skipped", path, unexpected);
                }
            }

            // for convenience create an alphabetized list also
            themeList = new ArrayList<>(this.themeMap.values());
            themeList.sort(Comparator.comparing(SharedTheme::getName));
            log.info("Successfully loaded {} shared blog themes.", themeList.size());
        } else {
            log.info("No shared blog themes detected at path {}, none will be loaded", blogThemePath);
        }
    }

    /**
     * Get the SharedTheme object with the given id.
     *
     * @return theme The SharedTheme object with the given id.
     * @throws IllegalArgumentException If the named theme cannot be found.
     **/
    public SharedTheme getSharedTheme(String id) {
        SharedTheme theme = this.themeMap.get(id);
        if (theme == null) {
            throw new IllegalArgumentException("Couldn't find theme [" + id + "]");
        }
        return theme;
    }

    /**
     * Get the WeblogTheme for a given weblog.
     *
     * @param weblog The weblog to get the theme for.
     * @return WeblogTheme The theme to be used for the given weblog
     */
    public WeblogTheme getWeblogTheme(Weblog weblog) {
        WeblogTheme weblogTheme = null;

        SharedTheme staticTheme = this.themeMap.get(weblog.getTheme());
        if (staticTheme != null) {
            weblogTheme = new WeblogTheme(weblogTemplateRepository, weblog, staticTheme);
        } else {
            log.warn("Unable to find shared theme {}", weblog.getTheme());
        }

        return weblogTheme;
    }

    /**
     * Get a list of all shared themes that are currently enabled. This list is
     * ordered alphabetically by default.
     *
     * @return List A list of SharedTheme objects which are enabled.
     */
    public List<SharedTheme> getEnabledSharedThemesList() {
        return themeList;
    }

    /**
     * Create a weblog template (database-stored, weblog-specific)
     * from a shared (file) template
     *
     * @param weblog         The weblog to import the template into
     * @param sharedTemplate The sharedTemplate that should copied from
     * @return WeblogTemplate instance, not persisted to the database.
     * (Caller is expected to do persistence if and when desired.)
     */
    public WeblogTemplate createWeblogTemplate(Weblog weblog, Template sharedTemplate) {
        WeblogTemplate weblogTemplate = new WeblogTemplate();
        weblogTemplate.setDerivation(Template.Derivation.OVERRIDDEN);
        weblogTemplate.setWeblog(weblog);
        weblogTemplate.setRole(sharedTemplate.getRole());
        weblogTemplate.setName(sharedTemplate.getName());
        weblogTemplate.setDescription(sharedTemplate.getDescription());
        weblogTemplate.setLastModified(Instant.now());
        weblogTemplate.setTemplate(sharedTemplate.getTemplate());
        return weblogTemplate;
    }

    private SharedTheme loadThemeData(String themePath) throws Exception {
        SharedTheme sharedTheme;
        String themeJson = themePath + "theme.json";

        try (InputStream is = servletContext.getResourceAsStream(themeJson)) {
            if (is != null) {
                sharedTheme = objectMapper.readValue(is, SharedTheme.class);
                sharedTheme.setThemeDir(themePath);

                // load resource representing preview image
                String previewFilePath = sharedTheme.getThemeDir() + sharedTheme.getPreviewImagePath();

                try (InputStream test = servletContext.getResourceAsStream(previewFilePath)) {
                    if (test == null) {
                        log.warn("Couldn't find theme [{}] thumbnail at path [{}]", sharedTheme.getName(),
                                previewFilePath);
                    }
                }

                // create the templates based on the theme descriptor data
                boolean hasWeblogTemplate = false;
                for (SharedTemplate template : sharedTheme.getTemplates()) {

                    // one and only one template with action "weblog" allowed
                    if (Role.WEBLOG.equals(template.getRole())) {
                        if (hasWeblogTemplate) {
                            throw new IllegalStateException(
                                    "Theme has more than one template with action of 'weblog'");
                        } else {
                            hasWeblogTemplate = true;
                        }
                    }

                    if (!loadTemplateSource(sharedTheme.getThemeDir(), template)) {
                        throw new IllegalStateException(
                                "Couldn't load template [" + template.getContentsFile() + "]");
                    }

                    // this template ID used by template resolvers to retrieve the template.
                    template.setId(sharedTheme.getId() + ":" + template.getName());
                }

                if (!hasWeblogTemplate) {
                    throw new IllegalStateException(
                            "Theme " + sharedTheme.getName() + " has no template with 'weblog' action");
                }

                log.info("Loaded {}", sharedTheme);
            } else {
                throw new IllegalStateException("Theme JSON " + themeJson + " not found");
            }
        }
        return sharedTheme;
    }

    private boolean loadTemplateSource(String loadThemeDir, SharedTemplate sharedTemplate) throws IOException {
        String resourcePath = loadThemeDir + sharedTemplate.getContentsFile();
        InputStream stream = servletContext.getResourceAsStream(resourcePath);
        if (stream == null) {
            return false;
        }

        String contents = IOUtils.toString(stream);
        if (contents == null) {
            log.error("Couldn't load template resource [{}]", resourcePath);
            sharedTemplate.setTemplate("");
        } else {
            sharedTemplate.setTemplate(contents);
        }
        return contents != null;
    }
}