it.tidalwave.northernwind.frontend.ui.component.sitemap.DefaultSitemapViewController.java Source code

Java tutorial

Introduction

Here is the source code for it.tidalwave.northernwind.frontend.ui.component.sitemap.DefaultSitemapViewController.java

Source

/*
 * #%L
 * *********************************************************************************************************************
 *
 * NorthernWind - lightweight CMS
 * http://northernwind.tidalwave.it - git clone https://bitbucket.org/tidalwave/northernwind-src.git
 * %%
 * Copyright (C) 2011 - 2016 Tidalwave s.a.s. (http://tidalwave.it)
 * %%
 * *********************************************************************************************************************
 *
 * 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.
 *
 * *********************************************************************************************************************
 *
 * $Id$
 *
 * *********************************************************************************************************************
 * #L%
 */
package it.tidalwave.northernwind.frontend.ui.component.sitemap;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import com.google.common.base.Predicate;
import org.springframework.beans.factory.annotation.Configurable;
import it.tidalwave.util.Key;
import it.tidalwave.util.NotFoundException;
import it.tidalwave.role.Composite.VisitorSupport;
import it.tidalwave.northernwind.core.model.HttpStatusException;
import it.tidalwave.northernwind.core.model.ResourceProperties;
import it.tidalwave.northernwind.core.model.Site;
import it.tidalwave.northernwind.core.model.SiteNode;
import it.tidalwave.northernwind.frontend.ui.Layout;
import it.tidalwave.northernwind.frontend.ui.component.Properties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import static it.tidalwave.northernwind.frontend.ui.component.sitemap.SitemapViewController.*;

/***********************************************************************************************************************
 *
 * @author  Fabrizio Giudici
 * @version $Id$
 *
 **********************************************************************************************************************/
@Configurable
@RequiredArgsConstructor
@Slf4j
public class DefaultSitemapViewController implements SitemapViewController {
    @Nonnull
    protected final SitemapView view;

    @Nonnull
    private final Site site;

    /*******************************************************************************************************************
     *
     * Initializes this controller.
     *
     ******************************************************************************************************************/
    @PostConstruct
    protected void initialize() throws Exception {
        final StringBuilder builder = new StringBuilder();
        builder.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
        builder.append("<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n");

        site.find(SiteNode.class).doWithResults(new Predicate<SiteNode>() {
            @Override
            public boolean apply(final @Nonnull SiteNode siteNode) {
                try {
                    final Layout layout = siteNode.getLayout();

                    // Prevents infinite recursion
                    if (!layout.getTypeUri().startsWith("http://northernwind.tidalwave.it/component/Sitemap/")) {
                        // FIXME: should probably skip children of sitenodes with managePathParams
                        // FIXME: for instance, Calendar would benefit
                        // FIXME: Would Blog benefit? It should, as it manages its own children
                        // FIXME: Places and Themes should move managePathParams=true to each children
                        // FIXME: Problem, the root gallery needs managePathParams=true to load images.xml
                        log.debug(">>>> sitemap processing {} / layout {} ...", siteNode.getRelativeUri(), layout);

                        appendUrl(builder, siteNode, null);

                        layout.accept(new VisitorSupport<Layout, Void>() {
                            @Override
                            public void visit(final @Nonnull Layout childLayout) {
                                try {
                                    final Object controller = childLayout.createViewAndController(siteNode)
                                            .getController();

                                    if (controller instanceof CompositeSiteNodeController) {
                                        for (final SiteNode childSiteNode : ((CompositeSiteNodeController) controller)
                                                .findChildrenSiteNodes().results()) {
                                            appendUrl(builder, siteNode, childSiteNode);
                                        }
                                    }
                                } catch (HttpStatusException e) {
                                    log.warn("sitemap for {} threw {}", siteNode.getRelativeUri(), e.toString());
                                } catch (Exception e) {
                                    log.warn("Skipped item because of {} - root cause {}", e,
                                            rootCause(e).toString());
                                }
                            }

                            @Override
                            public Void getValue() {
                                return null;
                            }
                        });
                    }
                } catch (IOException e) {
                    log.warn("", e);
                } catch (NotFoundException e) {
                    log.warn("", e);
                }

                return false;
            }
        });

        builder.append("</urlset>\n");
        view.setContent(builder.toString());
        view.setMimeType("application/xml");
    }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    private void appendUrl(final @Nonnull StringBuilder builder, final @Nonnull SiteNode siteNode,
            final @Nullable SiteNode childSiteNode) throws IOException {
        final SiteNode n = (childSiteNode != null) ? childSiteNode : siteNode;
        final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        final ResourceProperties properties = n.getProperties();
        //
        // FIXME: if you put the sitemap property straightly into the child site node, you can simplify a lot,
        // just using a single property and only peeking into a single node
        final Key<String> priorityKey = (childSiteNode == null) ? PROPERTY_SITEMAP_PRIORITY
                : PROPERTY_SITEMAP_CHILDREN_PRIORITY;
        final float sitemapPriority = Float.parseFloat(siteNode.getProperties().getProperty(priorityKey, "0.5"));

        if (sitemapPriority > 0) {
            builder.append("  <url>\n");
            builder.append(String.format("    <loc>%s</loc>%n", site.createLink(n.getRelativeUri())));
            builder.append(String.format("    <lastmod>%s</lastmod>%n",
                    getSiteNodeDateTime(properties).format(dateTimeFormatter)));
            builder.append(String.format("    <changefreq>%s</changefreq>%n",
                    properties.getProperty(PROPERTY_SITEMAP_CHANGE_FREQUENCY, "daily")));
            builder.append(String.format("    <priority>%s</priority>%n", Float.toString(sitemapPriority)));
            builder.append("  </url>\n");
        }
    }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    private ZonedDateTime getSiteNodeDateTime(final @Nonnull ResourceProperties properties) {
        try {
            final String string = properties.getProperty(Properties.PROPERTY_LATEST_MODIFICATION_DATE);
            return ZonedDateTime.parse(string, DateTimeFormatter.ISO_DATE_TIME);
        } catch (NotFoundException e) {
        } catch (IOException e) {
            log.warn("", e);
        }

        return Instant.ofEpochMilli(0).atZone(ZoneId.of("GMT"));
    }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    private static Throwable rootCause(final @Nonnull Throwable t) {
        final Throwable cause = t.getCause();
        return (cause != null) ? rootCause(cause) : t;
    }
}