View Javadoc

1   /*
2    * Copyright 2004-2005, University Health Network.  All rights reserved. Distributed under the BSD 
3    * license (see http://opensource.org/licenses/bsd-license.php).
4    *  
5    * Created on 6-Dec-2004
6    */
7   package ca.uhn.cache.impl;
8   
9   import java.util.Arrays;
10  import java.util.Date;
11  
12  import ca.uhn.cache.IDimension;
13  import ca.uhn.cache.IPointQueryParam;
14  import ca.uhn.cache.IQueryParam;
15  
16  /***
17   * A <code>IPointQueryParam</code> that selects data items with values along 
18   * a certain dimension exactly equal to a certain <code>Date</code> value.  
19   * 
20   * @author <a href="mailto:bryan.tripp@uhn.on.ca">Bryan Tripp</a>
21   * @author <a href="mailto:alexei.guevara@uhn.on.ca">Alexei Guevara</a> 
22   * @version $Revision: 1.1 $ updated on $Date: 2005/01/24 22:52:33 $ by $Author: bryan_tripp $
23   */
24  public class DateParam extends AbstractQueryParam implements IPointQueryParam {
25  
26      private final Date myValue;
27  
28      /***
29       * Creates a new <code>DateParam</code>.
30       * 
31       * @param theDimension The dimension where this parameter is difined.
32       * @param theValue The value of this parameter. 
33       */
34      public DateParam( IDimension theDimension, Date theValue ) {
35          super( theDimension );
36          
37          assert theValue != null;
38          
39          myValue = theValue;
40      }
41  
42      /***
43       * {@inheritDoc}
44       */
45      public boolean intersects(IQueryParam theParam) {
46          boolean retVal = false;
47          
48          if (super.intersects(theParam)) {
49              DateParam saturation =  new DateParam(this.getDimension(), new Date(1));
50              if (getDistance(theParam, saturation) == 0) {
51                  retVal = true;
52              }
53          }
54          
55          return retVal;
56      }
57  
58      /***
59       * @return Returns the value.
60       */
61      public Date getValue() {
62          return myValue;
63      }
64  
65      /*** 
66       * @see ca.uhn.cache.IQueryParam#getDistance(ca.uhn.cache.IQueryParam, ca.uhn.cache.IQueryParam)
67       */
68      public float getDistance(IQueryParam theParam, IQueryParam theSaturationPoint) {
69          checkCompatibility(theParam, this.getDimension());
70          checkCompatibility(theSaturationPoint, this.getDimension());
71          
72          if ( !(theSaturationPoint instanceof DateParam) ) {
73              throw new IllegalArgumentException("Saturation point should be a DateParam");
74          }
75  
76          long here = this.getValue().getTime();
77          long there = 0;
78          if (theParam instanceof DateParam) {
79              there = ((DateParam) theParam).getValue().getTime();
80          } else if (theParam instanceof DateRangeParam) {
81              DateRangeParam range = (DateRangeParam) theParam;
82              if (range.getStart().getTime() <= here && range.getEnd().getTime() >= here) {
83                  return 0; //NOTE SHORTCUT
84              } else if (range.getStart().getTime() > here) {
85                  there = range.getStart().getTime();                
86              } else {
87                  there = range.getEnd().getTime();
88              }            
89          }
90          
91          long difference = Math.abs(here - there);
92          long saturation = ((DateParam) theSaturationPoint).getValue().getTime();
93          
94          return getDistance(difference, saturation);
95      }
96      
97      /***
98       * @param theDifference a difference (ms) between two times
99       * @param theSaturation the difference that defines the distance 1
100      * @return a monotonically increasing function of the difference, which 
101      *      is near-linear below the saturation, and approaches 1 for higher values
102      */
103     protected static float getDistance(long theDifference, long theSaturation) {
104         return (float) (1 - Math.exp(-(float)theDifference / theSaturation));  
105     }
106 
107     /*** 
108      * @see ca.uhn.cache.IQueryParam#merge(ca.uhn.cache.IQueryParam)
109      */
110     public IQueryParam merge(IQueryParam theParam) {
111         checkCompatibility(theParam, this.getDimension());
112         
113         Date[] edges = null;
114         if (theParam instanceof DateParam) {
115             DateParam that = (DateParam) theParam;
116             edges = new Date[] {this.getValue(), that.getValue()};
117         } else if (theParam instanceof DateRangeParam) {
118             DateRangeParam that = (DateRangeParam) theParam;
119             edges = new Date[] {this.getValue(), that.getStart(), that.getEnd()};
120         }         
121         
122         Arrays.sort(edges);
123         return new DateRangeParam(this.getDimension(), edges[0], edges[edges.length-1]);                
124     }
125     
126     /***
127      * @param theParam another IQueryParam with which to check compatibility for merge() 
128      *      and distance()
129      * @param theDimension the dimension the param is expected to belong to
130      * @throws IllegalArgumentException if the given param is not of the given dimension
131      *      or is not either a DateParam or DateRangeParam
132      */
133     protected static void checkCompatibility(IQueryParam theParam, IDimension theDimension) {
134         if (theParam == null) {
135             throw new IllegalArgumentException("IQueryParam can not be null");
136         }
137         
138         if ( !(theParam instanceof DateParam) && !(theParam instanceof DateRangeParam) ) {
139             throw new IllegalArgumentException("Incompatible with " 
140                     + theParam.getClass().getName());            
141         }
142         
143         if ( !theDimension.equals(theParam.getDimension()) ) {
144             throw new IllegalArgumentException("Dimensions don't match: " + theDimension.getName()
145                     + " vs " + theParam.getDimension().getName());
146         }
147     }
148 }