/* * * Copyright (C) 2007-2015 Licensed to the Comunes Association (CA) under * one or more contributor license agreements (see COPYRIGHT for details). * The CA licenses this file to you under the GNU Affero General Public * License version 3, (the "License"); you may not use this file except in * compliance with the License. This file is part of kune. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package cc.kune.core.server.searcheable; import java.io.File; import java.net.MalformedURLException; import java.util.Date; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.waveprotocol.box.server.persistence.PersistenceException; import org.waveprotocol.box.server.persistence.file.FileUtils; import cc.kune.core.client.state.SiteTokens; import cc.kune.core.server.LogThis; import cc.kune.core.server.persist.KuneTransactional; import cc.kune.core.server.properties.KuneProperties; import cc.kune.core.server.utils.AbsoluteFileDownloadUtils; import cc.kune.core.shared.domain.GroupListMode; import cc.kune.core.shared.dto.GroupType; import cc.kune.domain.Container; import cc.kune.domain.Content; import cc.kune.domain.Group; import cc.kune.domain.finders.ContainerFinder; import cc.kune.domain.finders.ContentFinder; import cc.kune.domain.finders.GroupFinder; import com.google.inject.Inject; import com.google.inject.Singleton; import com.redfin.sitemapgenerator.ChangeFreq; import com.redfin.sitemapgenerator.WebSitemapGenerator; import com.redfin.sitemapgenerator.WebSitemapUrl; // TODO: Auto-generated Javadoc /** * The Class SiteMapServlet generate a sitemap.xml for the kune site * http://en.wikipedia.org/wiki/Sitemaps * * Inspired in: http://betweengo.com/category/java/servlet/ and for large sites: * http://dynamical.biz/blog/seo-technical/sitemap-strategy-large-sites-17.html * * @author vjrj@ourproject.org (Vicente J. Ruiz Jurado) */ @Singleton @LogThis public class SiteMapGenerator implements SiteMapGeneratorMBean { /** The Constant CONTENTS_PRIORITY. */ private static final Double CONTENTS_PRIORITY = 0.8; /** The Constant GROUPS_PRIORITY. */ private static final Double GROUPS_PRIORITY = 0.9; /** The Constant LIMIT_OF_QUERY. */ private static final int LIMIT_OF_QUERY = 100; /** The Constant LOG. */ public static final Log LOG = LogFactory.getLog(SiteMapGenerator.class); /** The Constant SITE_PRIORITY. */ private static final double SITE_PRIORITY = 1.0; /** The Constant siteUrls. */ public static final String[] siteUrls = new String[] { SiteTokens.HOME, SiteTokens.GROUP_HOME, SiteTokens.ABOUT_KUNE, SiteTokens.ASK_RESET_PASSWD, SiteTokens.NEW_GROUP, SiteTokens.REGISTER, SiteTokens.RESET_PASSWD, SiteTokens.SIGN_IN }; /** The container finder. */ private final ContainerFinder containerFinder; /** The content finder. */ private final ContentFinder contentFinder; /** The dir. */ private File dir; /** The file download utils. */ private final AbsoluteFileDownloadUtils fileDownloadUtils; /** The group finder. */ private final GroupFinder groupFinder; /** The site url. */ private final String siteUrl; /** * Instantiates a new site map generator. * * @param props * the props * @param groupFinder * the group finder * @param contentFinder * the content finder * @param containerFinder * the container finder * @param fileDownloadUtils * the file download utils */ @Inject public SiteMapGenerator(final KuneProperties props, final GroupFinder groupFinder, final ContentFinder contentFinder, final ContainerFinder containerFinder, final AbsoluteFileDownloadUtils fileDownloadUtils) { this.groupFinder = groupFinder; this.contentFinder = contentFinder; this.containerFinder = containerFinder; this.fileDownloadUtils = fileDownloadUtils; siteUrl = props.get(KuneProperties.SITE_URL); final String dirName = props.get(KuneProperties.SITEMAP_DIR); try { dir = FileUtils.createDirIfNotExists(dirName, ""); } catch (final PersistenceException e) { LOG.error("Error generating sitemap", e); } } /** * Count not closed groups. * * @return the long */ @KuneTransactional private Long countNotClosedGroups() { return groupFinder.countExceptType(GroupType.CLOSED); } /* * (non-Javadoc) * * @see cc.kune.core.server.searcheable.SiteMapGeneratorMBean#generate() */ @Override public void generate() { LOG.info("Starting to generate sitemap"); final Date now = new Date(); try { final WebSitemapGenerator wsg = new WebSitemapGenerator(siteUrl, dir); LOG.info("Initialize sitemap"); // Site urls hashs (#signin, #register, etc) for (final String siteHash : siteUrls) { final String siteUri = fileDownloadUtils.getUrl(siteHash); final WebSitemapUrl url = new WebSitemapUrl.Options(siteUri).lastMod(now).priority(SITE_PRIORITY).changeFreq( ChangeFreq.WEEKLY).build(); wsg.addUrl(url); } // Groups LOG.info("Start groups procesing for sitema generation"); final Long count = countNotClosedGroups(); int i = 0; while (i < count) { LOG.info("Procesing groups for site map til: " + i + LIMIT_OF_QUERY); final List<Group> groups = getGroups(i); for (final Group group : groups) { final String groupUri = fileDownloadUtils.getUrl(group.getStateToken().toString()); final WebSitemapUrl groupUrl = new WebSitemapUrl.Options(groupUri).lastMod(now).priority( GROUPS_PRIORITY).changeFreq(ChangeFreq.DAILY).build(); wsg.addUrl(groupUrl); // Containers for (final Container container : getContainers(group)) { if (container.getAccessLists().getViewers().getMode().equals(GroupListMode.EVERYONE)) { final String containerUri = fileDownloadUtils.getUrl(container.getStateToken().toString()); final WebSitemapUrl containerUrl = new WebSitemapUrl.Options(containerUri).lastMod(now).priority( CONTENTS_PRIORITY).changeFreq(ChangeFreq.DAILY).build(); wsg.addUrl(containerUrl); } } // Contents for (final Content content : getContents(group)) { if (content.getAccessLists().getViewers().getMode().equals(GroupListMode.EVERYONE)) { final String contentUri = fileDownloadUtils.getUrl(content.getStateToken().toString()); final WebSitemapUrl contentUrl = new WebSitemapUrl.Options(contentUri).lastMod( new Date(content.getModifiedOn())).priority(CONTENTS_PRIORITY).changeFreq( ChangeFreq.DAILY).build(); wsg.addUrl(contentUrl); } } i += LIMIT_OF_QUERY; } } wsg.write(); } catch (final MalformedURLException e) { LOG.error("Error generating sitemap. Malformed URL.", e); } } /** * Gets the containers. * * @param group * the group * @return the containers */ @KuneTransactional private List<Container> getContainers(final Group group) { return containerFinder.allContainersInUserGroup(group.getId()); } /** * Gets the contents. * * @param group * the group * @return the contents */ @KuneTransactional private List<Content> getContents(final Group group) { return contentFinder.allContentsInUserGroup(group.getId()); } /** * Gets the groups. * * @param i * the i * @return the groups */ @KuneTransactional private List<Group> getGroups(final int i) { return groupFinder.getAllExcept(LIMIT_OF_QUERY, i, GroupType.CLOSED); } }