Source code: com/sun/xacml/cond/DateMathFunction.java
1
2 /*
3 * @(#)DateMathFunction.java
4 *
5 * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistribution of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistribution in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
18 * be used to endorse or promote products derived from this software without
19 * specific prior written permission.
20 *
21 * This software is provided "AS IS," without a warranty of any kind. ALL
22 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
23 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
24 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
25 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
26 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
27 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
28 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
29 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
30 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
31 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
32 *
33 * You acknowledge that this software is not designed or intended for use in
34 * the design, construction, operation or maintenance of any nuclear facility.
35 */
36
37 package com.sun.xacml.cond;
38
39 import com.sun.xacml.EvaluationCtx;
40
41 import com.sun.xacml.attr.AttributeValue;
42 import com.sun.xacml.attr.DateAttribute;
43 import com.sun.xacml.attr.DateTimeAttribute;
44 import com.sun.xacml.attr.DayTimeDurationAttribute;
45 import com.sun.xacml.attr.YearMonthDurationAttribute;
46
47 import java.util.Calendar;
48 import java.util.Collections;
49 import java.util.Date;
50 import java.util.GregorianCalendar;
51 import java.util.HashMap;
52 import java.util.HashSet;
53 import java.util.Iterator;
54 import java.util.List;
55 import java.util.Set;
56
57
58 /**
59 * A class that implements several of the date math functions. They
60 * all take two arguments. The first is a DateTimeAttribute or a
61 * DateAttribute (as the case may be) and the second is a
62 * DayTimeDurationAttribute or a YearMonthDurationAttribute (as
63 * the case may be). The function adds or subtracts the second
64 * argument to/from the first and returns a value of the same
65 * type as the first argument. If either of the arguments evaluates
66 * to indeterminate, an indeterminate result is returned.
67 *
68 * @since 1.0
69 * @author Steve Hanna
70 * @author Seth Proctor
71 */
72 public class DateMathFunction extends FunctionBase
73 {
74
75 /**
76 * Standard identifier for the dateTime-add-dayTimeDuration function.
77 */
78 public static final String NAME_DATETIME_ADD_DAYTIMEDURATION =
79 FUNCTION_NS + "dateTime-add-dayTimeDuration";
80
81 /**
82 * Standard identifier for the dateTime-subtract-dayTimeDuration function.
83 */
84 public static final String NAME_DATETIME_SUBTRACT_DAYTIMEDURATION =
85 FUNCTION_NS + "dateTime-subtract-dayTimeDuration";
86
87 /**
88 * Standard identifier for the dateTime-add-yearMonthDuration function.
89 */
90 public static final String NAME_DATETIME_ADD_YEARMONTHDURATION =
91 FUNCTION_NS + "dateTime-add-yearMonthDuration";
92
93 /**
94 * Standard identifier for the dateTime-subtract-yearMonthDuration
95 * function.
96 */
97 public static final String NAME_DATETIME_SUBTRACT_YEARMONTHDURATION =
98 FUNCTION_NS + "dateTime-subtract-yearMonthDuration";
99
100 /**
101 * Standard identifier for the date-add-yearMonthDuration function.
102 */
103 public static final String NAME_DATE_ADD_YEARMONTHDURATION =
104 FUNCTION_NS + "date-add-yearMonthDuration";
105
106 /**
107 * Standard identifier for the date-subtract-yearMonthDuration function.
108 */
109 public static final String NAME_DATE_SUBTRACT_YEARMONTHDURATION =
110 FUNCTION_NS + "date-subtract-yearMonthDuration";
111
112 // private identifiers for the supported functions
113 private static final int ID_DATETIME_ADD_DAYTIMEDURATION = 0;
114 private static final int ID_DATETIME_SUBTRACT_DAYTIMEDURATION = 1;
115 private static final int ID_DATETIME_ADD_YEARMONTHDURATION = 2;
116 private static final int ID_DATETIME_SUBTRACT_YEARMONTHDURATION = 3;
117 private static final int ID_DATE_ADD_YEARMONTHDURATION = 4;
118 private static final int ID_DATE_SUBTRACT_YEARMONTHDURATION = 5;
119
120 // Argument types
121 private static final String dateTimeDayTimeDurationArgTypes [] =
122 { DateTimeAttribute.identifier,
123 DayTimeDurationAttribute.identifier };
124 private static final String dateTimeYearMonthDurationArgTypes [] =
125 { DateTimeAttribute.identifier,
126 YearMonthDurationAttribute.identifier };
127 private static final String dateYearMonthDurationArgTypes [] =
128 { DateAttribute.identifier,
129 YearMonthDurationAttribute.identifier };
130
131 // nothing here uses a bag
132 private static final boolean bagParams [] = { false, false };
133
134 // Argument types for this object
135 private String [] argTypes = null;
136
137 // mapping from name to provide identifiers and argument types
138 private static HashMap idMap;
139 private static HashMap typeMap;
140
141 /**
142 * Static initializer to setup the id and type maps
143 */
144 static {
145 idMap = new HashMap();
146
147 idMap.put(NAME_DATETIME_ADD_DAYTIMEDURATION,
148 new Integer(ID_DATETIME_ADD_DAYTIMEDURATION));
149 idMap.put(NAME_DATETIME_SUBTRACT_DAYTIMEDURATION,
150 new Integer(ID_DATETIME_SUBTRACT_DAYTIMEDURATION));
151 idMap.put(NAME_DATETIME_ADD_YEARMONTHDURATION,
152 new Integer(ID_DATETIME_ADD_YEARMONTHDURATION));
153 idMap.put(NAME_DATETIME_SUBTRACT_YEARMONTHDURATION,
154 new Integer(ID_DATETIME_SUBTRACT_YEARMONTHDURATION));
155 idMap.put(NAME_DATE_ADD_YEARMONTHDURATION,
156 new Integer(ID_DATE_ADD_YEARMONTHDURATION));
157 idMap.put(NAME_DATE_SUBTRACT_YEARMONTHDURATION,
158 new Integer(ID_DATE_SUBTRACT_YEARMONTHDURATION));
159
160 typeMap = new HashMap();
161
162 typeMap.put(NAME_DATETIME_ADD_DAYTIMEDURATION,
163 dateTimeDayTimeDurationArgTypes);
164 typeMap.put(NAME_DATETIME_SUBTRACT_DAYTIMEDURATION,
165 dateTimeDayTimeDurationArgTypes);
166 typeMap.put(NAME_DATETIME_ADD_YEARMONTHDURATION,
167 dateTimeYearMonthDurationArgTypes);
168 typeMap.put(NAME_DATETIME_SUBTRACT_YEARMONTHDURATION,
169 dateTimeYearMonthDurationArgTypes);
170 typeMap.put(NAME_DATE_ADD_YEARMONTHDURATION,
171 dateYearMonthDurationArgTypes);
172 typeMap.put(NAME_DATE_SUBTRACT_YEARMONTHDURATION,
173 dateYearMonthDurationArgTypes);
174 };
175
176 /**
177 * Creates a new <code>DateMathFunction</code> object.
178 *
179 * @param functionName the standard XACML name of the function to be
180 * handled by this object, including the full namespace
181 *
182 * @throws IllegalArgumentException if the function is unknown
183 */
184 public DateMathFunction(String functionName) {
185 super(functionName, getId(functionName),
186 getArgumentTypes(functionName), bagParams,
187 getReturnType(functionName), false);
188 }
189
190 /**
191 * Private helper that returns the internal identifier used for the
192 * given standard function.
193 */
194 private static int getId(String functionName) {
195 Integer i = (Integer)(idMap.get(functionName));
196
197 if (i == null)
198 throw new IllegalArgumentException("unknown datemath function " +
199 functionName);
200
201 return i.intValue();
202 }
203
204 /**
205 * Private helper that returns the types used for the given standard
206 * function. Note that this doesn't check on the return value since the
207 * method always is called after getId, so we assume that the function
208 * is present.
209 */
210 private static String [] getArgumentTypes(String functionName) {
211 return (String [])(typeMap.get(functionName));
212 }
213
214 /**
215 * Private helper that returns the return type for the given standard
216 * function. Note that this doesn't check on the return value since the
217 * method always is called after getId, so we assume that the function
218 * is present.
219 */
220 private static String getReturnType(String functionName) {
221 if (functionName.equals(NAME_DATE_ADD_YEARMONTHDURATION) ||
222 functionName.equals(NAME_DATE_SUBTRACT_YEARMONTHDURATION))
223 return DateAttribute.identifier;
224 else
225 return DateTimeAttribute.identifier;
226 }
227
228 /**
229 * Returns a <code>Set</code> containing all the function identifiers
230 * supported by this class.
231 *
232 * @return a <code>Set</code> of <code>String</code>s
233 */
234 public static Set getSupportedIdentifiers() {
235 return Collections.unmodifiableSet(idMap.keySet());
236 }
237
238 /**
239 * Evaluate the function, using the specified parameters.
240 *
241 * @param inputs a <code>List</code> of <code>Evaluatable</code>
242 * objects representing the arguments passed to the function
243 * @param context an <code>EvaluationCtx</code> so that the
244 * <code>Evaluatable</code> objects can be evaluated
245 * @return an <code>EvaluationResult</code> representing the
246 * function's result
247 */
248 public EvaluationResult evaluate(List inputs, EvaluationCtx context) {
249
250 // Evaluate the arguments
251 AttributeValue [] argValues = new AttributeValue[inputs.size()];
252 EvaluationResult result = evalArgs(inputs, context, argValues);
253 if (result != null)
254 return result;
255
256 // Now that we have real values, perform the date math operation.
257 AttributeValue attrResult = null;
258
259 switch (getFunctionId()) {
260 // These two functions are basically the same except for sign.
261 // And they both need to deal with sign anyway, so they share
262 // their code.
263 case ID_DATETIME_ADD_DAYTIMEDURATION:
264 case ID_DATETIME_SUBTRACT_DAYTIMEDURATION: {
265 DateTimeAttribute dateTime = (DateTimeAttribute) argValues[0];
266 DayTimeDurationAttribute duration =
267 (DayTimeDurationAttribute) argValues[1];
268
269 // Decide what sign goes with duration
270 int sign = 1;
271 if (getFunctionId() == ID_DATETIME_SUBTRACT_DAYTIMEDURATION)
272 sign = -sign;
273 if (duration.isNegative())
274 sign = -sign;
275 long millis = sign * duration.getTotalSeconds();
276 long nanoseconds = dateTime.getNanoseconds();
277 nanoseconds = nanoseconds + (sign * duration.getNanoseconds());
278 if (nanoseconds >= 1000000000) {
279 nanoseconds -= 1000000000;
280 millis += 1000;
281 }
282 if (nanoseconds < 0) {
283 nanoseconds += 1000000000;
284 millis -= 1000;
285 }
286 millis = millis + dateTime.getValue().getTime();
287
288 attrResult = new DateTimeAttribute(new Date(millis),
289 (int) nanoseconds,
290 dateTime.getTimeZone(),
291 dateTime.
292 getDefaultedTimeZone());
293
294 break;
295 }
296 case ID_DATETIME_ADD_YEARMONTHDURATION:
297 case ID_DATETIME_SUBTRACT_YEARMONTHDURATION: {
298 DateTimeAttribute dateTime = (DateTimeAttribute) argValues[0];
299 YearMonthDurationAttribute duration =
300 (YearMonthDurationAttribute) argValues[1];
301
302 // Decide what sign goes with duration
303 int sign = 1;
304 if (getFunctionId() == ID_DATETIME_SUBTRACT_YEARMONTHDURATION)
305 sign = -sign;
306 if (duration.isNegative())
307 sign = -sign;
308
309 // Add (or subtract) the years and months.
310 Calendar cal = new GregorianCalendar();
311 cal.setTime(dateTime.getValue());
312 long years = sign * duration.getYears();
313 long months = sign * duration.getMonths();
314 if ((years > Integer.MAX_VALUE) || (years < Integer.MIN_VALUE))
315 return makeProcessingError("years too large");
316 if ((months > Integer.MAX_VALUE) || (months < Integer.MIN_VALUE))
317 return makeProcessingError("months too large");
318
319 cal.add(Calendar.YEAR, (int) years);
320 cal.add(Calendar.MONTH, (int) months);
321
322 attrResult = new DateTimeAttribute(cal.getTime(),
323 dateTime.getNanoseconds(),
324 dateTime.getTimeZone(),
325 dateTime.
326 getDefaultedTimeZone());
327
328 break;
329 }
330 case ID_DATE_ADD_YEARMONTHDURATION:
331 case ID_DATE_SUBTRACT_YEARMONTHDURATION: {
332 DateAttribute date = (DateAttribute) argValues[0];
333 YearMonthDurationAttribute duration =
334 (YearMonthDurationAttribute) argValues[1];
335
336 // Decide what sign goes with duration
337 int sign = 1;
338 if (getFunctionId() == ID_DATE_SUBTRACT_YEARMONTHDURATION)
339 sign = -sign;
340 if (duration.isNegative())
341 sign = -sign;
342
343 // Add (or subtract) the years and months.
344 Calendar cal = new GregorianCalendar();
345 cal.setTime(date.getValue());
346 long years = sign * duration.getYears();
347 long months = sign * duration.getMonths();
348 if ((years > Integer.MAX_VALUE) || (years < Integer.MIN_VALUE))
349 return makeProcessingError("years too large");
350 if ((months > Integer.MAX_VALUE) || (months < Integer.MIN_VALUE))
351 return makeProcessingError("months too large");
352
353 cal.add(Calendar.YEAR, (int) years);
354 cal.add(Calendar.MONTH, (int) months);
355
356 attrResult = new DateAttribute(cal.getTime(),
357 date.getTimeZone(),
358 date.getDefaultedTimeZone());
359
360 break;
361 }
362 }
363
364 return new EvaluationResult(attrResult);
365 }
366 }