View Javadoc

1   package org.apache.jcs.utils.key;
2   
3   import java.text.ParseException;
4   import java.util.Calendar;
5   import java.util.Date;
6   
7   import org.apache.commons.logging.Log;
8   import org.apache.commons.logging.LogFactory;
9   import org.apache.jcs.utils.date.DateFormatter;
10  
11  /**
12   * This can create and parse request ids.  You can use it to generate keys that contain a create time stamp.
13   * <p>
14   * You can set a system property called "KEY_LEAD_NUMBER" to override the lead number. The value
15   * must be a simple int from 1 to 9.
16   */
17  public final class KeyGeneratorUtil
18  {
19      /** The logger. */
20      private static final Log log = LogFactory.getLog( KeyGeneratorUtil.class );
21  
22      /** a temporary counter for generating request ids. */
23      private static int requestCounter = 0;
24  
25      /** last reset time. */
26      private static long lastCounterResetTime = System.currentTimeMillis();
27  
28      /** defaults to 2 hours. */
29      private static final long DEFAULT_COUNTER_RESET_INTERVAL_MILLIS = 2 * 60 * 60 * 1000;
30  
31      /** How often should we reset the counter. */
32      protected static long counterResetIntervalMillis = DEFAULT_COUNTER_RESET_INTERVAL_MILLIS;
33  
34      /** The size of the data portion. */
35      private static final int LENGTH_OF_DATE_STRING = 8;
36  
37      /**
38       * The name of the system property that can be used to override the default. This allows us to
39       * run multiple instance on a machine.
40       */
41      public static final String KEY_LEAD_NUMBER_PROPERTY_NAME = "KEY_LEAD_NUMBER";
42  
43      /** The default lead number. */
44      public static final int DEFAULT_LEAD_NUMBER = 3;
45  
46      /** We lead with a number so it can be converted to a number. This is the prefix to all ids. */
47      protected static int leadNumber = DEFAULT_LEAD_NUMBER;
48  
49      static
50      {
51          setLeadFromSystemProperty();
52      }
53  
54      /** Sets the lead number from a system property */
55      protected static void setLeadFromSystemProperty()
56      {
57          String leadString = System.getProperty( KEY_LEAD_NUMBER_PROPERTY_NAME, String.valueOf( DEFAULT_LEAD_NUMBER ) );
58          if ( log.isInfoEnabled() )
59          {
60              log.info( "leadString = [" + leadString + "]" );
61          }
62          try
63          {
64              leadNumber = Integer.parseInt( leadString );
65          }
66          catch ( NumberFormatException e )
67          {
68              log.error( "Problem parsing lead number system property value. [" + leadString + "]", e );
69          }
70      }
71  
72      /**
73       * Creates a query id in the format 1001010121712345 where the first 8 digits (10010101) is a 8
74       * digit number where: 1 is a padding digit and 001 is the first day of the year. The next 3
75       * digits (217) are the decimal representation of the last byte of data in the machine ip (for
76       * example 192.168.1.2 will be 002). The remaining digits (ex. 12345) are some unique number.
77       * These come from a counter that is reset every 2 hours.
78       * <p>
79       * @return long
80       */
81      public static String generateRequestId()
82      {
83          int counter = getNextRequestCounter();
84  
85          Date d = new Date();
86          String dateString = DateFormatter.getDddHHmm( d );
87          String finalOctetOfIp = org.apache.jcs.utils.net.AddressUtil.obtainFinalThreeDigitsOfAddressAsString();
88          String queryId = leadNumber + dateString + finalOctetOfIp + counter;
89          return queryId;
90      }
91  
92      /**
93       * This DddHHmm.
94       * <p>
95       * This has to get the current year and set it, since the source data does not have the year.
96       * <p>
97       * @param queryId queryId
98       * @return now if we can't parse, else the data from the query id.
99       * @throws ParseException ParseException
100      */
101     public static Date getDateOfShopFromRequestId( String queryId )
102         throws ParseException
103     {
104         Date date = null;
105         if ( queryId != null )
106         {
107             if ( queryId.length() >= LENGTH_OF_DATE_STRING )
108             {
109                 Calendar cal = Calendar.getInstance();
110                 int year = cal.get( Calendar.YEAR );
111                 int dayOfYear;
112                 int hour;
113                 int minute;
114 
115                 try
116                 {
117                     dayOfYear = Integer.parseInt( queryId.substring( 1, 4 ) );
118                     hour = Integer.parseInt( queryId.substring( 4, 6 ) );
119                     minute = Integer.parseInt( queryId.substring( 6, 8 ) );
120                 }
121                 catch ( NumberFormatException e )
122                 {
123                     throw new ParseException( "Error reading date/hour/minute from input string [" + queryId + "]", 0 );
124                 }
125 
126                 cal.set( Calendar.YEAR, year );
127                 cal.set( Calendar.DAY_OF_YEAR, dayOfYear );
128                 cal.set( Calendar.HOUR_OF_DAY, hour );
129                 cal.set( Calendar.MINUTE, minute );
130                 date = cal.getTime();
131             }
132             else
133             {
134                 throw new ParseException( "The input string is not long enough [" + queryId + "]", queryId.length() );
135             }
136         }
137         else
138         {
139             throw new ParseException( "Can't parse a null string.", 0 );
140         }
141         return date;
142     }
143 
144     /**
145      * Automatically increment and return the request counter. If the last counter reset was more
146      * than the interval, reset the counter.
147      * <p>
148      * @return The incremented count.
149      */
150     protected static synchronized int getNextRequestCounter()
151     {
152         long now = System.currentTimeMillis();
153         if ( ( now - KeyGeneratorUtil.lastCounterResetTime ) > KeyGeneratorUtil.counterResetIntervalMillis )
154         {
155             resetCounter();
156         }
157         return ++requestCounter;
158     }
159 
160     /** reset the counter and the reset time. */
161     protected static synchronized void resetCounter()
162     {
163         KeyGeneratorUtil.lastCounterResetTime = System.currentTimeMillis();
164         KeyGeneratorUtil.requestCounter = 0;
165     }
166 }