Skip to content
Permalink
Browse files

Added pinging support for Google and Bing.

  • Loading branch information...
jfendler committed Feb 21, 2016
1 parent 3b4573c commit d2f94683792dea13279fd4580ab1b9dc267d32c2
25 LICENSE
@@ -174,28 +174,3 @@
of your accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work.

To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright {yyyy} {name of copyright owner}

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.
@@ -83,7 +83,7 @@ public class MyContoller {
// create multiple entries in the sitemap for a controller method with `@PathParam` arguments
@Sitemap(multiPageProvider="modules.MyMultiPageProvider")
public void productDetails(Context context, @PathParam("productId") long productId) {
public Result productDetails(Context context, @PathParam("productId") long productId) {
// ...
}
}
10 pom.xml
@@ -1,4 +1,5 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jensfendler</groupId>
<artifactId>ninja-sitemap</artifactId>
@@ -103,7 +104,12 @@
<artifactId>jsitemapgenerator</artifactId>
<version>${jsitemapgenerator.version}</version>
</dependency>

<dependency>
<!-- Needed for supporting 'pings' to Google and Bing -->
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.1</version>
</dependency>
</dependencies>

<build>
@@ -18,6 +18,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Inject;
import com.jensfendler.ninjasitemap.controller.NinjaSitemapController;

import ninja.Router;
@@ -30,12 +31,13 @@
*/
public class NinjaSitemapRoutes implements ApplicationRoutes {

protected static final Logger LOG = LoggerFactory.getLogger(NinjaSitemapRoutes.class);
public static final String KEY_SITEMAP_ROUTE = "ninja.sitemap.route";

protected static final String KEY_SITEMAP_ROUTE = "ninja.sitemap.route";
public static final String DEFAULT_SITEMAP_ROUTE = "/sitemap.xml";

protected static final String DEFAULT_SITEMAP_ROUTE = "/sitemap.xml";
protected static final Logger LOG = LoggerFactory.getLogger(NinjaSitemapRoutes.class);

@Inject
protected NinjaProperties ninjaProperties;

/**
@@ -52,15 +52,15 @@ public SitemapRouteDetails get() {
return srd;
} catch (ClassNotFoundException e) {
LOG.error("Could not load " + SitemapRouteDetails.class.getSimpleName() + " implementation " + sdpClassName + ". Please check your '"
+ KEY_SITEMAP_ROUTE_DETAILS_IMPL + "' setting in application.conf. Will use default provider for now.", e);
+ KEY_SITEMAP_ROUTE_DETAILS_IMPL + "' setting in application.conf.", e);
return null;
} catch (InstantiationException e) {
LOG.error("Could not instantiate " + SitemapRouteDetails.class.getSimpleName() + " implementation " + sdpClassName + ".", e);
return null;
} catch (IllegalAccessException e) {
LOG.error("Could not instantiate " + SitemapRouteDetails.class.getSimpleName() + " implementation " + sdpClassName + ".", e);
return null;
}
}
}
}

}
@@ -18,19 +18,22 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.jensfendler.ninjasitemap.SitemapRouteDetails;
import com.jensfendler.ninjasitemap.NinjaSitemapRoutes;
import com.jensfendler.ninjasitemap.SitemapEntry;
import com.jensfendler.ninjasitemap.SitemapMultiPageProvider;
import com.jensfendler.ninjasitemap.annotations.Sitemap;

import cz.jiripinkas.jsitemapgenerator.ChangeFreq;
import cz.jiripinkas.jsitemapgenerator.WebPage;
import cz.jiripinkas.jsitemapgenerator.exception.GWTException;
import cz.jiripinkas.jsitemapgenerator.generator.SitemapGenerator;
import ninja.Context;
import ninja.Result;
@@ -61,10 +64,44 @@
*/
private static final String KEY_SITEMAP_PREFIX = "ninja.sitemap.prefix";

/**
* An application.conf property to control the expiry time of the sitemap in
* Ninja's cache. This value should preferably be less than half the
* shortest 'changeFrequency' of your sitemap entries.
*/
private static final String KEY_NINJA_SITEMAP_EXPIRED = "ninja.sitemap.expires";

/**
* The default expiry time of the sitemap string in Ninja's cache. Defaults
* to 6 hours ("6h"). The string must be in a format compatible with the
* {@link NinjaCache} methods.
*/
private static final String DEFAULT_SITEMAP_EXPIRY_TIME = "12h";

/**
* If this application.conf property is 'true', the Google search engine is
* informed of updates to the sitemap. Default: false.
*/
private static final String KEY_PING_GOOGLE = "ninja.sitemap.ping.google";

/**
* If this application.conf property is 'true', the Bing search engine is
* informed of updates to the sitemap. Default: false.
*/
private static final String KEY_PING_BING = "ninja.sitemap.ping.bing";

/**
* The cache key to use for the sitemap.
*/
private static final String SITEMAP_CACHE_KEY = NinjaSitemapController.class.getSimpleName() + "-sitemap";

/**
* If this key is set to 'false', no warnings will be logged when using a
* {@link SitemapMultiPageProvider} for a non-dynamic route. If this
* property is 'true' (the default), a warning will be logged.
*/
private static final String KEY_SHOW_MPP_WARNINGS = "ninja.sitemap.multiPageWarnings";

@Inject
protected NinjaCache cache;

@@ -87,7 +124,7 @@
public Result getSitemapXml(Context context) {

// attempt a cache lookup first.
String sitemapString = (String) cache.get(getSitemapCacheKey());
String sitemapString = (String) cache.get(SITEMAP_CACHE_KEY);

if (sitemapString == null) {
// sitemap is not in cache. re-create.
@@ -117,7 +154,7 @@ private String createSitemap(Context context) {

siteUrlPrefix = siteUrlPrefix.replaceAll("/$", "");

SitemapGenerator generator = new SitemapGenerator(siteUrlPrefix);
final SitemapGenerator generator = new SitemapGenerator(siteUrlPrefix);

for (Route route : router.getRoutes()) {
Sitemap sitemap = route.getControllerMethod().getAnnotation(Sitemap.class);
@@ -135,8 +172,49 @@ private String createSitemap(Context context) {
String sitemapString = generator.constructSitemapString();
String sitemapCacheExpires = ninjaProperties.getWithDefault(KEY_NINJA_SITEMAP_EXPIRED,
DEFAULT_SITEMAP_EXPIRY_TIME);
cache.safeAdd(getSitemapCacheKey(), sitemapString, sitemapCacheExpires);
LOG.info("Sitemap has been updated and cached. Will be recreated in {}.", sitemapCacheExpires);
boolean isCached = cache.safeSet(SITEMAP_CACHE_KEY, sitemapString, sitemapCacheExpires);
if (isCached) {
LOG.info("Sitemap has been updated and cached. Will be recreated in {}.", sitemapCacheExpires);
} else {
// perhaps this is the first time cache
LOG.warn("Sitemap has been updated and will be delivered, but could not be cached.");
}

// check if we should ping google/bing for the updated sitemap
final boolean shouldPingGoogle = ninjaProperties.getBooleanWithDefault(KEY_PING_GOOGLE, false);
final boolean shouldPingBing = ninjaProperties.getBooleanWithDefault(KEY_PING_BING, false);
if (shouldPingGoogle || shouldPingBing) {

String sitemapRoute = ninjaProperties.getWithDefault(NinjaSitemapRoutes.KEY_SITEMAP_ROUTE,
NinjaSitemapRoutes.DEFAULT_SITEMAP_ROUTE);
if (!sitemapRoute.startsWith("/")) {
sitemapRoute = "/" + sitemapRoute;
}
final String sitemapUrl = siteUrlPrefix + sitemapRoute;

// pinging search engines will take some time. run this in a new
// thread so that the current request can immediately be served.
Executors.defaultThreadFactory().newThread(new Runnable() {
public void run() {
if (shouldPingGoogle) {
try {
generator.pingGoogle(sitemapUrl);
LOG.info("Google search engine has been notified of updated sitemap at '{}'.", sitemapUrl);
} catch (GWTException e) {
LOG.warn("Failed to ping Google with updated sitemap.", e);
}
}
if (shouldPingBing) {
try {
generator.pingBing(sitemapUrl);
LOG.info("Bing search engine has been notified of updated sitemap at '{}'.", sitemapUrl);
} catch (GWTException e) {
LOG.warn("Failed to ping Google with updated sitemap.", e);
}
}
}
}).start();
}

// return the sitemap.xml data as a string
return sitemapString;
@@ -169,9 +247,9 @@ private String createSitemap(Context context) {
.forName(smppClassName);
SitemapMultiPageProvider smpp = smppClass.newInstance();

if (!dynamicRoute) {
// notice that this is strange - creating multiple sitemap
// entries for a non-dynamic route.
if (!dynamicRoute && ninjaProperties.getBooleanWithDefault(KEY_SHOW_MPP_WARNINGS, true)) {
// using a MultiPageProvider for a non-dynamic route is
// usually strange. warn about it.
LOG.warn(
"Using {} to create sitemap entries for non-dynamic route {} to {}.{}. Is this really intended?",
smppClassName, route.getUri(), route.getControllerClass().getName(),
@@ -307,13 +385,4 @@ private boolean includeInSitemap(Sitemap sitemap, Route route) {
}
}

/**
* Gets the key to use for caching the complete sitemap string (XML data).
*
* @return the cache key for the sitemap data
*/
public static String getSitemapCacheKey() {
return NinjaSitemapController.class.getName() + ".sitemap";
}

}

0 comments on commit d2f9468

Please sign in to comment.
You can’t perform that action at this time.