org.apache.taglibs.standard.tlv.JstlBaseTLV Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jakarta.servlet.jsp.jstl Show documentation
Show all versions of jakarta.servlet.jsp.jstl Show documentation
Jakarta Standard Tag Library Implementation
/*
* Copyright (c) 1997-2020 Oracle and/or its affiliates. All rights reserved.
* Copyright 2004 The Apache Software Foundation
*
* Licensed 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 org.apache.taglibs.standard.tlv;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Vector;
import jakarta.servlet.jsp.JspException;
import jakarta.servlet.jsp.tagext.PageData;
import jakarta.servlet.jsp.tagext.TagData;
import jakarta.servlet.jsp.tagext.TagLibraryValidator;
import jakarta.servlet.jsp.tagext.ValidationMessage;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.taglibs.standard.lang.support.ExpressionEvaluator;
import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
import org.apache.taglibs.standard.resources.Resources;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* A base class to support SAX-based validation in JSTL.
*
* @author Shawn Bayern
*/
public abstract class JstlBaseTLV extends TagLibraryValidator {
//*********************************************************************
// Implementation Overview
/*
* We essentially just run the page through a SAX parser, handling
* the callbacks that interest us. The SAX parser is supplied by
* subclasses using the protected getHandler() method.
*/
protected abstract DefaultHandler getHandler();
//*********************************************************************
// Constants
// parameter names
private final String EXP_ATT_PARAM = "expressionAttributes";
// attributes
protected static final String VAR = "var";
protected static final String SCOPE = "scope";
//scopes
protected static final String PAGE_SCOPE = "page";
protected static final String REQUEST_SCOPE = "request";
protected static final String SESSION_SCOPE = "session";
protected static final String APPLICATION_SCOPE = "application";
// Relevant URIs
protected final String JSP = "http://java.sun.com/JSP/Page";
// types of sub-classes - used on method validate()
private static final int TYPE_UNDEFINED = 0;
protected static final int TYPE_CORE = 1;
protected static final int TYPE_FMT = 2;
protected static final int TYPE_SQL = 3;
protected static final int TYPE_XML = 4;
// which tlv is being validated
private int tlvType = TYPE_UNDEFINED;
//*********************************************************************
// Validation and configuration state (protected)
protected String uri; // our taglib's uri (as passed by JSP container on XML View)
protected String prefix; // our taglib's prefix
protected Vector messageVector; // temporary error messages
protected Map config; // configuration (Map of Sets)
protected boolean failed; // have we failed >0 times?
protected String lastElementId; // the last element we've seen
//*********************************************************************
// Constructor and lifecycle management
public JstlBaseTLV() {
super();
init();
}
private synchronized void init() {
messageVector = null;
prefix = null;
config = null;
}
public void release() {
super.release();
init();
}
//*********************************************************************
// Validation entry point - this method is called by the sub-classes to
// do the validation.
public synchronized ValidationMessage[] validate(
int type, String prefix, String uri, PageData page) {
try {
this.tlvType = type;
this.uri = uri;
// initialize
messageVector = new Vector();
// save the prefix
this.prefix = prefix;
// parse parameters if necessary
try {
if (config == null)
configure((String) getInitParameters().get(EXP_ATT_PARAM));
} catch (NoSuchElementException ex) {
// parsing error
return vmFromString(
Resources.getMessage("TLV_PARAMETER_ERROR",
EXP_ATT_PARAM));
}
// get a handler
DefaultHandler h = getHandler();
// parse the page
SAXParserFactory f = SAXParserFactory.newInstance();
f.setValidating(false);
f.setNamespaceAware(true);
SAXParser p = f.newSAXParser();
p.parse(page.getInputStream(), h);
if (messageVector.size() == 0)
return null;
else
return vmFromVector(messageVector);
} catch (SAXException ex) {
return vmFromString(ex.toString());
} catch (ParserConfigurationException ex) {
return vmFromString(ex.toString());
} catch (IOException ex) {
return vmFromString(ex.toString());
}
}
//*********************************************************************
// Protected utility functions
// delegate validation to the appropriate expression language
protected String validateExpression(
String elem, String att, String expr) {
// let's just use the cache kept by the ExpressionEvaluatorManager
ExpressionEvaluator current;
try {
current =
ExpressionEvaluatorManager.getEvaluatorByName(
ExpressionEvaluatorManager.EVALUATOR_CLASS);
} catch (JspException ex) {
// (using JspException here feels ugly, but it's what EEM uses)
return ex.getMessage();
}
String response = current.validate(att, expr);
if (response == null)
return response;
else
return "tag = '" + elem + "' / attribute = '" + att + "': "
+ response;
}
// utility methods to help us match elements in our tagset
protected boolean isTag(String tagUri,
String tagLn,
String matchUri,
String matchLn) {
if (tagUri == null
|| tagUri.length() == 0
|| tagLn == null
|| matchUri == null
|| matchLn == null)
return false;
// match beginning of URI since some suffix *_rt tags can
// be nested in EL enabled tags as defined by the spec
if (tagUri.length() > matchUri.length()) {
return (tagUri.startsWith(matchUri) && tagLn.equals(matchLn));
} else {
return (matchUri.startsWith(tagUri) && tagLn.equals(matchLn));
}
}
protected boolean isJspTag(String tagUri, String tagLn, String target) {
return isTag(tagUri, tagLn, JSP, target);
}
private boolean isTag( int type, String tagUri, String tagLn, String target) {
return ( this.tlvType == type && isTag(tagUri, tagLn, this.uri, target) );
}
protected boolean isCoreTag(String tagUri, String tagLn, String target) {
return isTag( TYPE_CORE, tagUri, tagLn, target );
}
protected boolean isFmtTag(String tagUri, String tagLn, String target) {
return isTag( TYPE_FMT, tagUri, tagLn, target );
}
protected boolean isSqlTag(String tagUri, String tagLn, String target) {
return isTag( TYPE_SQL, tagUri, tagLn, target );
}
protected boolean isXmlTag(String tagUri, String tagLn, String target) {
return isTag( TYPE_XML, tagUri, tagLn, target );
}
// utility method to determine if an attribute exists
protected boolean hasAttribute(Attributes a, String att) {
return (a.getValue(att) != null);
}
/*
* method to assist with failure [ as if it's not easy enough
* already :-) ]
*/
protected synchronized void fail(String message) {
failed = true;
messageVector.add(new ValidationMessage(lastElementId, message));
}
// returns true if the given attribute name is specified, false otherwise
protected boolean isSpecified(TagData data, String attributeName) {
return (data.getAttribute(attributeName) != null);
}
// returns true if the 'scope' attribute is valid
protected boolean hasNoInvalidScope(Attributes a) {
String scope = a.getValue(SCOPE);
if ((scope != null)
&& !scope.equals(PAGE_SCOPE)
&& !scope.equals(REQUEST_SCOPE)
&& !scope.equals(SESSION_SCOPE)
&& !scope.equals(APPLICATION_SCOPE))
return false;
return true;
}
// returns true if the 'var' attribute is empty
protected boolean hasEmptyVar(Attributes a) {
if ("".equals(a.getValue(VAR)))
return true;
return false;
}
// returns true if the 'scope' attribute is present without 'var'
protected boolean hasDanglingScope(Attributes a) {
return (a.getValue(SCOPE) != null && a.getValue(VAR) == null);
}
// retrieves the local part of a QName
protected String getLocalPart(String qname) {
int colon = qname.indexOf(":");
if (colon == -1)
return qname;
else
return qname.substring(colon + 1);
}
//*********************************************************************
// Miscellaneous utility functions
// parses our configuration parameter for element:attribute pairs
private void configure(String info) {
// construct our configuration map
config = new HashMap();
// leave the map empty if we have nothing to configure
if (info == null)
return;
// separate parameter into space-separated tokens and store them
StringTokenizer st = new StringTokenizer(info);
while (st.hasMoreTokens()) {
String pair = st.nextToken();
StringTokenizer pairTokens = new StringTokenizer(pair, ":");
String element = pairTokens.nextToken();
String attribute = pairTokens.nextToken();
Object atts = config.get(element);
if (atts == null) {
atts = new HashSet();
config.put(element, atts);
}
((Set) atts).add(attribute);
}
}
// constructs a ValidationMessage[] from a single String and no ID
static ValidationMessage[] vmFromString(String message) {
return new ValidationMessage[] {
new ValidationMessage(null, message)
};
}
// constructs a ValidationMessage[] from a ValidationMessage Vector
static ValidationMessage[] vmFromVector(Vector v) {
ValidationMessage[] vm = new ValidationMessage[v.size()];
for (int i = 0; i < vm.length; i++)
vm[i] = (ValidationMessage) v.get(i);
return vm;
}
}