| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| |
| package freemarker.core; |
| |
| import java.util.Date; |
| import java.util.List; |
| import java.util.TimeZone; |
| |
| import freemarker.template.AdapterTemplateModel; |
| import freemarker.template.SimpleDate; |
| import freemarker.template.SimpleScalar; |
| import freemarker.template.TemplateDateModel; |
| import freemarker.template.TemplateException; |
| import freemarker.template.TemplateMethodModelEx; |
| import freemarker.template.TemplateModel; |
| import freemarker.template.TemplateModelException; |
| import freemarker.template.TemplateScalarModel; |
| import freemarker.template._TemplateAPI; |
| import freemarker.template._VersionInts; |
| import freemarker.template.utility.DateUtil; |
| import freemarker.template.utility.UnrecognizedTimeZoneException; |
| |
| /** |
| * A holder for built-ins that operate exclusively on date left-hand values. |
| */ |
| class BuiltInsForDates { |
| |
| static class dateType_if_unknownBI extends BuiltIn { |
| |
| private final int dateType; |
| |
| dateType_if_unknownBI(int dateType) { |
| this.dateType = dateType; |
| } |
| |
| @Override |
| TemplateModel _eval(Environment env) |
| throws TemplateException { |
| TemplateModel model = target.eval(env); |
| if (model instanceof TemplateDateModel) { |
| TemplateDateModel tdm = (TemplateDateModel) model; |
| int tdmDateType = tdm.getDateType(); |
| if (tdmDateType != TemplateDateModel.UNKNOWN) { |
| return tdm; |
| } |
| return new SimpleDate(EvalUtil.modelToDate(tdm, target), dateType); |
| } else { |
| throw BuiltInForDate.newNonDateException(env, model, target); |
| } |
| } |
| |
| protected TemplateModel calculateResult(Date date, int dateType, Environment env) throws TemplateException { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| } |
| |
| /** |
| * Implements {@code ?iso(timeZone)}. |
| */ |
| static class iso_BI extends AbstractISOBI { |
| |
| class Result implements TemplateMethodModelEx { |
| private final Date date; |
| private final int dateType; |
| private final Environment env; |
| |
| Result(Date date, int dateType, Environment env) { |
| this.date = date; |
| this.dateType = dateType; |
| this.env = env; |
| } |
| |
| @Override |
| public Object exec(List args) throws TemplateModelException { |
| checkMethodArgCount(args, 1); |
| |
| TemplateModel tzArgTM = (TemplateModel) args.get(0); |
| TimeZone tzArg; |
| Object adaptedObj; |
| if (tzArgTM instanceof AdapterTemplateModel |
| && (adaptedObj = |
| ((AdapterTemplateModel) tzArgTM) |
| .getAdaptedObject(TimeZone.class)) |
| instanceof TimeZone) { |
| tzArg = (TimeZone) adaptedObj; |
| } else if (tzArgTM instanceof TemplateScalarModel) { |
| String tzName = EvalUtil.modelToString((TemplateScalarModel) tzArgTM, null, null); |
| try { |
| tzArg = DateUtil.getTimeZone(tzName); |
| } catch (UnrecognizedTimeZoneException e) { |
| throw new _TemplateModelException( |
| "The time zone string specified for ?", key, |
| "(...) is not recognized as a valid time zone name: ", |
| new _DelayedJQuote(tzName)); |
| } |
| } else { |
| throw _MessageUtil.newMethodArgUnexpectedTypeException( |
| "?" + key, 0, "string or java.util.TimeZone", tzArgTM); |
| } |
| |
| return new SimpleScalar(DateUtil.dateToISO8601String( |
| date, |
| dateType != TemplateDateModel.TIME, |
| dateType != TemplateDateModel.DATE, |
| shouldShowOffset(date, dateType, env), |
| accuracy, |
| tzArg, |
| env.getISOBuiltInCalendarFactory())); |
| } |
| |
| } |
| |
| iso_BI(Boolean showOffset, int accuracy) { |
| super(showOffset, accuracy); |
| } |
| |
| @Override |
| protected TemplateModel calculateResult( |
| Date date, int dateType, Environment env) |
| throws TemplateException { |
| checkDateTypeNotUnknown(dateType); |
| return new Result(date, dateType, env); |
| } |
| |
| } |
| |
| /** |
| * Implements {@code ?iso_utc} and {@code ?iso_local} variants, but not |
| * {@code ?iso(timeZone)}. |
| */ |
| static class iso_utc_or_local_BI extends AbstractISOBI { |
| |
| private final boolean useUTC; |
| |
| iso_utc_or_local_BI(Boolean showOffset, int accuracy, boolean useUTC) { |
| super(showOffset, accuracy); |
| this.useUTC = useUTC; |
| } |
| |
| @Override |
| protected TemplateModel calculateResult( |
| Date date, int dateType, Environment env) |
| throws TemplateException { |
| checkDateTypeNotUnknown(dateType); |
| return new SimpleScalar(DateUtil.dateToISO8601String( |
| date, |
| dateType != TemplateDateModel.TIME, |
| dateType != TemplateDateModel.DATE, |
| shouldShowOffset(date, dateType, env), |
| accuracy, |
| useUTC |
| ? DateUtil.UTC |
| : env.shouldUseSQLDTTZ(date.getClass()) |
| ? env.getSQLDateAndTimeTimeZone() |
| : env.getTimeZone(), |
| env.getISOBuiltInCalendarFactory())); |
| } |
| |
| } |
| |
| // Can't be instantiated |
| private BuiltInsForDates() { } |
| |
| static abstract class AbstractISOBI extends BuiltInForDate { |
| protected final Boolean showOffset; |
| protected final int accuracy; |
| |
| protected AbstractISOBI(Boolean showOffset, int accuracy) { |
| this.showOffset = showOffset; |
| this.accuracy = accuracy; |
| } |
| |
| protected void checkDateTypeNotUnknown(int dateType) |
| throws TemplateException { |
| if (dateType == TemplateDateModel.UNKNOWN) { |
| throw new _MiscTemplateException(new _ErrorDescriptionBuilder( |
| "The value of the following has unknown date type, but ?", key, |
| " needs a value where it's known if it's a date (no time part), time, or date-time value:" |
| ).blame(target).tip(_MessageUtil.UNKNOWN_DATE_TYPE_ERROR_TIP)); |
| } |
| } |
| |
| protected boolean shouldShowOffset(Date date, int dateType, Environment env) { |
| if (dateType == TemplateDateModel.DATE) { |
| return false; // ISO 8061 doesn't allow zone for date-only values |
| } else if (this.showOffset != null) { |
| return this.showOffset.booleanValue(); |
| } else { |
| // java.sql.Time values meant to carry calendar field values only, so we don't show offset for them. |
| return !(date instanceof java.sql.Time |
| && _TemplateAPI.getTemplateLanguageVersionAsInt(this) >= _VersionInts.V_2_3_21); |
| } |
| } |
| |
| } |
| |
| } |