/*
* 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.ext.jsp;
import java.io.
IOException;
import java.io.
Writer;
import java.util.
List;
import java.util.
Map;
import freemarker.core.
BugException;
import freemarker.core.
Environment;
import freemarker.core.
_UnexpectedTypeErrorExplainerTemplateModel;
import freemarker.ext.beans.
SimpleMethodModel;
import freemarker.template.
TemplateDirectiveBody;
import freemarker.template.
TemplateDirectiveModel;
import freemarker.template.
TemplateException;
import freemarker.template.
TemplateMethodModelEx;
import freemarker.template.
TemplateModel;
import freemarker.template.
TemplateModelException;
import freemarker.template.
TemplateSequenceModel;
import freemarker.template.
TemplateTransformModel;
import freemarker.template.utility.
ClassUtil;
/**
* Used when a custom JSP tag and an EL function uses the same name in a tag library, to create a single FTL value from
* the two. As FTL as no separate namespace for "tags" and functions, both aspect has to be implemented by the same
* value.
*
* @since 2.3.25
*/
@
SuppressWarnings("rawtypes")
class
CustomTagAndELFunctionCombiner {
/**
* @param customTag
* Either a {@link TemplateDirectiveModel} or a {@link TemplateTransformModel}.
*/
static
TemplateModel combine(
TemplateModel customTag,
TemplateMethodModelEx elFunction) {
if (
customTag instanceof
TemplateDirectiveModel) {
return
elFunction instanceof
SimpleMethodModel //
? new
TemplateDirectiveModelAndSimpleMethodModel( //
(
TemplateDirectiveModel)
customTag, (
SimpleMethodModel)
elFunction) //
: new
TemplateDirectiveModelAndTemplateMethodModelEx( //
(
TemplateDirectiveModel)
customTag,
elFunction);
} else if (
customTag instanceof
TemplateTransformModel) {
return (
elFunction instanceof
SimpleMethodModel)
? new
TemplateTransformModelAndSimpleMethodModel( //
(
TemplateTransformModel)
customTag, (
SimpleMethodModel)
elFunction) //
: new
TemplateTransformModelAndTemplateMethodModelEx( //
(
TemplateTransformModel)
customTag,
elFunction);
} else {
throw new
BugException(
"Unexpected custom JSP tag class: " +
ClassUtil.
getShortClassNameOfObject(
customTag));
}
}
/**
* Tells if the value can be used as the "custom tag" parameter to
* {@link #combine(TemplateModel, TemplateMethodModelEx)}.
*/
static boolean
canBeCombinedAsCustomTag(
TemplateModel tm) {
return (
tm instanceof
TemplateDirectiveModel ||
tm instanceof
TemplateTransformModel)
&& !(
tm instanceof
CombinedTemplateModel);
}
/**
* Tells if the value can be used as the "EL function" parameter to
* {@link #combine(TemplateModel, TemplateMethodModelEx)}.
*/
static boolean
canBeCombinedAsELFunction(
TemplateModel tm) {
return
tm instanceof
TemplateMethodModelEx && !(
tm instanceof
CombinedTemplateModel);
}
private static class
CombinedTemplateModel {
// Marker only
};
private static class
TemplateDirectiveModelAndSimpleMethodModel extends
CombinedTemplateModel
implements
TemplateDirectiveModel,
TemplateMethodModelEx,
TemplateSequenceModel,
_UnexpectedTypeErrorExplainerTemplateModel {
private final
TemplateDirectiveModel templateDirectiveModel;
private final
SimpleMethodModel simpleMethodModel;
public
TemplateDirectiveModelAndSimpleMethodModel( //
TemplateDirectiveModel templateDirectiveModel,
SimpleMethodModel simpleMethodModel) {
this.
templateDirectiveModel =
templateDirectiveModel;
this.
simpleMethodModel =
simpleMethodModel;
}
public
Object exec(
List arguments) throws
TemplateModelException {
return
simpleMethodModel.
exec(
arguments);
}
public void
execute(
Environment env,
Map params,
TemplateModel[]
loopVars,
TemplateDirectiveBody body)
throws
TemplateException,
IOException {
templateDirectiveModel.
execute(
env,
params,
loopVars,
body);
}
public
Object[]
explainTypeError(
Class[]
expectedClasses) {
return
simpleMethodModel.
explainTypeError(
expectedClasses);
}
public
TemplateModel get(int
index) throws
TemplateModelException {
return
simpleMethodModel.
get(
index);
}
public int
size() throws
TemplateModelException {
return
simpleMethodModel.
size();
}
}
private static class
TemplateDirectiveModelAndTemplateMethodModelEx extends
CombinedTemplateModel
implements
TemplateDirectiveModel,
TemplateMethodModelEx {
private final
TemplateDirectiveModel templateDirectiveModel;
private final
TemplateMethodModelEx templateMethodModelEx;
public
TemplateDirectiveModelAndTemplateMethodModelEx( //
TemplateDirectiveModel templateDirectiveModel,
TemplateMethodModelEx templateMethodModelEx) {
this.
templateDirectiveModel =
templateDirectiveModel;
this.
templateMethodModelEx =
templateMethodModelEx;
}
public
Object exec(
List arguments) throws
TemplateModelException {
return
templateMethodModelEx.
exec(
arguments);
}
public void
execute(
Environment env,
Map params,
TemplateModel[]
loopVars,
TemplateDirectiveBody body)
throws
TemplateException,
IOException {
templateDirectiveModel.
execute(
env,
params,
loopVars,
body);
}
}
private static class
TemplateTransformModelAndTemplateMethodModelEx extends
CombinedTemplateModel
implements
TemplateTransformModel,
TemplateMethodModelEx {
private final
TemplateTransformModel templateTransformModel;
private final
TemplateMethodModelEx templateMethodModelEx;
public
TemplateTransformModelAndTemplateMethodModelEx( //
TemplateTransformModel templateTransformModel,
TemplateMethodModelEx templateMethodModelEx) {
this.
templateTransformModel =
templateTransformModel;
this.
templateMethodModelEx =
templateMethodModelEx;
}
public
Object exec(
List arguments) throws
TemplateModelException {
return
templateMethodModelEx.
exec(
arguments);
}
public
Writer getWriter(
Writer out,
Map args) throws
TemplateModelException,
IOException {
return
templateTransformModel.
getWriter(
out,
args);
}
}
private static class
TemplateTransformModelAndSimpleMethodModel extends
CombinedTemplateModel
implements
TemplateTransformModel,
TemplateMethodModelEx,
TemplateSequenceModel,
_UnexpectedTypeErrorExplainerTemplateModel {
private final
TemplateTransformModel templateTransformModel;
private final
SimpleMethodModel simpleMethodModel;
public
TemplateTransformModelAndSimpleMethodModel( //
TemplateTransformModel templateTransformModel,
SimpleMethodModel simpleMethodModel) {
this.
templateTransformModel =
templateTransformModel;
this.
simpleMethodModel =
simpleMethodModel;
}
public
Object exec(
List arguments) throws
TemplateModelException {
return
simpleMethodModel.
exec(
arguments);
}
public
Object[]
explainTypeError(
Class[]
expectedClasses) {
return
simpleMethodModel.
explainTypeError(
expectedClasses);
}
public
TemplateModel get(int
index) throws
TemplateModelException {
return
simpleMethodModel.
get(
index);
}
public int
size() throws
TemplateModelException {
return
simpleMethodModel.
size();
}
public
Writer getWriter(
Writer out,
Map args) throws
TemplateModelException,
IOException {
return
templateTransformModel.
getWriter(
out,
args);
}
}
}