com.chiorichan.site.SiteManager.java Source code

Java tutorial

Introduction

Here is the source code for com.chiorichan.site.SiteManager.java

Source

/**
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright 2016 Chiori Greene a.k.a. Chiori-chan <me@chiorichan.com>
 * All Right Reserved.
 */
package com.chiorichan.site;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang3.Validate;

import com.chiorichan.AppConfig;
import com.chiorichan.Loader;
import com.chiorichan.configuration.file.YamlConfiguration;
import com.chiorichan.datastore.file.FileDatastore;
import com.chiorichan.lang.ApplicationException;
import com.chiorichan.lang.SiteException;
import com.chiorichan.lang.StartupException;
import com.chiorichan.logger.Log;
import com.chiorichan.logger.LogSource;
import com.chiorichan.services.AppManager;
import com.chiorichan.services.ObjectContext;
import com.chiorichan.services.ServiceManager;
import com.chiorichan.services.ServicePriority;
import com.chiorichan.services.ServiceProvider;
import com.chiorichan.tasks.TaskRegistrar;
import com.chiorichan.util.FileFunc;
import com.chiorichan.util.NetworkFunc;
import com.chiorichan.util.Pair;
import com.chiorichan.util.StringFunc;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Files;

/**
 * Manages and Loads Sites
 */
public class SiteManager implements ServiceProvider, LogSource, ServiceManager, TaskRegistrar {
    protected static File checkSiteRoot(String name) {
        File site = new File(Loader.getWebRoot(), name);

        FileFunc.setDirectoryAccessWithException(site);

        File publicDir = new File(site, "public/root");
        File resourceDir = new File(site, "resource");

        FileFunc.setDirectoryAccessWithException(publicDir);
        FileFunc.setDirectoryAccessWithException(resourceDir);

        return site;
    }

    public static void cleanupBackups(final String siteId, final String suffix, int limit) {
        File dir = new File(AppConfig.get().getDirectory("archive", "archive"), siteId);
        if (!dir.exists())
            return;
        File[] files = dir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.toLowerCase().endsWith(suffix);
            }
        });

        if (files == null || files.length < 1)
            return;

        // Delete all logs, no archiving!
        if (limit < 1) {
            for (File f : files)
                f.delete();
            return;
        }

        FileFunc.SortableFile[] sfiles = new FileFunc.SortableFile[files.length];

        for (int i = 0; i < files.length; i++)
            sfiles[i] = new FileFunc.SortableFile(files[i]);

        Arrays.sort(sfiles);

        if (sfiles.length > limit)
            for (int i = 0; i < sfiles.length - limit; i++)
                sfiles[i].f.delete();
    }

    public static Log getLogger() {
        return AppManager.manager(SiteManager.class).getLogger();
    }

    public static SiteManager instance() {
        return AppManager.manager(SiteManager.class).instance();
    }

    Map<String, Site> sites = Maps.newConcurrentMap();

    private SiteManager() {

    }

    public boolean delete(String siteId, boolean deleteFiles) throws SiteException {
        Validate.notNull(siteId);

        if (siteId.equals("default"))
            throw new SiteException("You can not delete the default site.");

        if (sites.containsKey(siteId)) {
            Site site = getSiteById(siteId);
            sites.remove(siteId);

            site.unload();

            if (site instanceof Site)
                site.getFile().delete();
            if (deleteFiles)
                site.directory().delete();
            return true;
        }

        return false;
    }

    public Site getDefaultSite() {
        return getSiteById("default");
    }

    public Map<String, Set<String>> getDomains() {
        return new HashMap<String, Set<String>>() {
            {
                for (Site s : sites.values())
                    for (Entry<String, Set<String>> es : s.getDomains().entrySet())
                        if (containsKey(es.getKey()))
                            get(es.getKey()).addAll(es.getValue());
                        else
                            put(es.getKey(), es.getValue());
            }
        };
    }

    @Override
    public String getLoggerId() {
        return "SiteMgr";
    }

    @Override
    public String getName() {
        return "SiteMgr";
    }

    public Site getSiteByDomain(String domain) {
        if (domain == null || domain.length() == 0)
            return getDefaultSite();

        Pair<String, SiteMapping> mapping = SiteMapping.get(domain);

        return mapping == null ? null : mapping.getValue().getSite();
    }

    public Site getSiteById(String siteId) {
        if (siteId == null || siteId.length() == 0 || siteId.equalsIgnoreCase("%"))
            siteId = "default";

        return sites.get(siteId.toLowerCase().trim());
    }

    public List<Site> getSiteByIp(String ip) {
        List<Site> matches = Lists.newArrayList();

        if (!NetworkFunc.isValidIPv4(ip) && !NetworkFunc.isValidIPv6(ip))
            throw new IllegalArgumentException("The provided ip addr does not match IPv4 or IPv6");

        for (Site site : getSites())
            if (site.getIps().contains(ip))
                matches.add(site);

        if (matches.size() == 0)
            matches.add(getDefaultSite());

        return matches;
    }

    public Collection<Site> getSites() {
        return Collections.unmodifiableCollection(sites.values());
    }

    @Override
    public void init() throws ApplicationException {
        AppManager.registerService(Site.class, this, new ObjectContext(this), ServicePriority.Normal);
        loadSites();
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    public void loadSites() throws ApplicationException {
        if (sites.size() > 0)
            throw new StartupException("Site manager already has sites loaded. You must unload first.");

        sites.put("default", new DefaultSite());

        FileDatastore ds = FileDatastore.loadDirectory(Loader.getWebRoot(), "(.*)/config.yaml");

        for (Entry<File, YamlConfiguration> entry : ds.asEntrySet()) {
            File configFile = entry.getKey();
            YamlConfiguration yaml = entry.getValue();

            if (!yaml.has("site.id"))
                if (yaml.has("site.siteId")) { // Temp until later version
                    yaml.set("site.id", yaml.get("site.siteId"));
                    yaml.set("site.siteId", null);
                }

            if (yaml.has("site.id")) {
                String id = yaml.getString("site.id").toLowerCase();
                String siteDir = StringFunc.regexCapture(configFile.getAbsolutePath(),
                        "\\/([^\\/]*)\\/config.yaml");

                if (!id.equals(siteDir)) {
                    getLogger().warning(String.format(
                            "We found a site configuration file at '%s' but the containing directory did not match the siteId of '%s', we will now correct this by moving the config to the correct directory.",
                            configFile.getAbsolutePath(), id));
                    File oldConfigFile = configFile;
                    configFile = new File(Loader.getWebRoot(), id + "/config.yaml");
                    try {
                        Files.move(oldConfigFile, configFile);
                    } catch (IOException e) {
                        getLogger().severe(
                                "We failed to move the configuration file, the site will not load until you manually correct the above issue.",
                                e);
                        continue;
                    }
                }

                try {
                    sites.put(id, new Site(configFile, yaml));
                } catch (SiteException e) {
                    getLogger().severe(String.format("Exception encountered while loading site '%s'", id), e);
                }
            } else
                getLogger().warning(
                        String.format("The site '%s' is missing the site id `site.id`, site will not be loaded.",
                                yaml.loadedFrom()));
        }
    }

    public List<Site> parseSites(String sites) {
        return parseSites(sites, "|");
    }

    public List<Site> parseSites(String sites, String regExSplit) {
        List<Site> siteList = Lists.newArrayList();
        String[] sitesArray = sites.split(regExSplit);

        for (String siteId : sitesArray) {
            Site site = getSiteById(siteId);
            if (site != null)
                siteList.add(site);
        }

        return siteList;
    }

    public void reload() throws ApplicationException {
        sites = new LinkedHashMap<String, Site>();
        init();
    }

    public void unloadSites() {
        for (Site site : sites.values())
            try {
                site.save(true);
            } catch (IOException e) {
                Log.get().severe(e);
            }

        sites.clear();
    }
}