package de.spieleck.servlets; import java.io.*; import java.util.ArrayList; import java.util.HashMap; import javax.servlet.*; import javax.servlet.http.*; /** * Simple Hack for a random redirection servlet. * * Setup in web.xml is as follows: * *
 *     <servlet-mapping url-pattern='rlink/*' servlet-name='rlink'/>
 *     <servlet>
 *       <servlet-name>rlink</servlet-name>
 *       <servlet-class>de.spieleck.servlets.RandomLink</servlet-class>
 *       <!-- Path to Configuration files (value is the default) -->
 *       <init-param>
 *           <param-name>basePath</param-name>
 *           <param-value>WEB-INF/randomLinkData</param-value>
 *       </init-param>
 *       <!-- Extension to path file (value is the default) -->
 *       <init-param>
 *           <param-name>configExt</param-name>
 *           <param-value>.lst</param-value>
 *       </init-param>
 *       <!-- Time to store the cookie (default one month) -->
 *       <init-param>
 *           <param-name>cookieTime</param-name>
 *           <param-value>2678400</param-value>
 *       </init-param>
 *     </servlet>
 * 
* * The servlet then accepts requests like *
 *   http://yourServer/yourApp/rlink/cname
 * 
* and looks for a configuration file at *
 *    ContextPath/WEB-INF/randomLinkData/cname.lst
 * 
* This configuraton file contains a mere list of URL's, * one per line. * * 27 Apr 2003 fixed synchronization. */ public class RandomLink extends HttpServlet { public static final String SERVLET = "RandomLink"; public final static String BASEPATH = "basePath"; public final static String CONFIGEXT = "configExt"; public final static String COOKIETIME = "cookieTime"; /** Keep track of known Configurations */ public static HashMap configs; /** Base path, where configurations are looked up from */ protected String basePath = null; /** Filename extension for configuration files */ protected String configExt = null; /** Expiration time for cookies. */ protected int cookieTime = 60*60*24*31; public RandomLink() { } /** * Init: Pull params from web.xml. */ public void init() throws ServletException { configs = new HashMap(); basePath = getServletConfig().getInitParameter(BASEPATH); configExt = getServletConfig().getInitParameter(CONFIGEXT); String h = getServletConfig().getInitParameter(COOKIETIME); if ( h != null ) try { cookieTime = Integer.parseInt(h); } catch ( NumberFormatException e ) { e.printStackTrace(); } log("Start: "+SERVLET +" "+BASEPATH+"="+basePath +" "+CONFIGEXT+"="+configExt +" "+COOKIETIME+"="+cookieTime ); if ( configExt == null ) configExt = ".lst"; if ( basePath == null ) basePath = "WEB-INF/randomLinkData"; basePath = getServletContext().getRealPath(basePath)+"/"; } /** * Process request, whatever type. */ public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { // --- Obtain Configuration matching request String confName = req.getPathInfo(); if ( confName == null ) confName = ""; else confName = confName.substring(1); Config config = getConfig(confName); if(config == null) { res.sendError(res.SC_EXPECTATION_FAILED, "Could not find config " + confName); return; } // --- Obtain next URL from either cookie or globals String cookieName = config.getCookieName(); Cookie myc = null; Cookie[] cookies = req.getCookies(); if ( cookies != null ) for (int i = 0; i < cookies.length; i++ ) if ( cookies[i].getName().equals(cookieName) ) { myc = cookies[i]; break; } String url = config.getNextURL(myc); // --- Reply, a cookie and a redirect myc = new Cookie(cookieName, url); myc.setMaxAge(cookieTime); res.addCookie(myc); res.sendRedirect(url); } /** * Obtain matching Configuration. * First try to retrieve it from HashMap if it hasn't changed * in between. If this fails, try to read the file. */ protected synchronized Config getConfig(String cname) { Config config = (Config) configs.get(cname); if( config != null ) { if ( ! config.isRecent() ) { configs.remove(cname); config = null; } } if ( config == null ) try { config = new Config(basePath, cname, configExt); configs.put(cname, config); } catch ( IOException io ) { io.printStackTrace(); return null; } return config; } /** * Subclass to contain configuration data */ protected static class Config { /** The file containing the configuration */ protected File configFile; /** Last time the config file was changed. */ protected long edited; /** Cookie sent to user for this configuration. */ protected String cookieName; /** Cyclical URL-Counter, for Clients which do not accept Cookies. */ protected int currentUrl; /** Alle the URLs we jump to. */ protected String[] urls; public Config(String bPath, String cname, String ext) throws IOException { configFile = new File(bPath+cname+ext); readConfig(); currentUrl = 0; cookieName = "rl."+cname+"."+cname.hashCode()+".c"; } public synchronized boolean isRecent() { return edited == configFile.lastModified(); } public String getCookieName() { return cookieName; } public synchronized int getURLCount() { return urls.length; } public String getNextURL(Cookie myc) { int i = 0; if ( myc == null ) i = nextUrlNo(); else { String u = myc.getValue(); for (i = 0; i < getURLCount(); i++) { if ( u.equals(urls[i]) ) break; } i = (i+1) % getURLCount(); } return urls[i]; } protected synchronized int nextUrlNo() { currentUrl = (currentUrl + 1) % getURLCount(); return currentUrl; } protected synchronized void readConfig() throws IOException { BufferedReader in = new BufferedReader(new FileReader(configFile)); String line = in.readLine(); ArrayList urlsa = new ArrayList(10); while ( line != null ) { urlsa.add(line); line = in.readLine(); } urls = new String[urlsa.size()]; urlsa.toArray((Object[])urls); // Keep timestamp of change edited = configFile.lastModified(); } } }