KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > taglibs > standard > tlv > JstlSqlTLV


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.taglibs.standard.tlv;
18
19 import java.util.Set JavaDoc;
20 import java.util.Stack JavaDoc;
21
22 import javax.servlet.jsp.tagext.PageData JavaDoc;
23 import javax.servlet.jsp.tagext.ValidationMessage JavaDoc;
24
25 import org.apache.taglibs.standard.resources.Resources;
26 import org.xml.sax.Attributes JavaDoc;
27 import org.xml.sax.helpers.DefaultHandler JavaDoc;
28
29 /**
30  * <p>A SAX-based TagLibraryValidator for the JSTL SQL tag library.
31  *
32  * @author Shawn Bayern
33  */

34 public class JstlSqlTLV extends JstlBaseTLV {
35
36     //*********************************************************************
37
// Constants
38

39     // tag names
40
private final String JavaDoc SETDATASOURCE = "setDataSource";
41     private final String JavaDoc QUERY = "query";
42     private final String JavaDoc UPDATE = "update";
43     private final String JavaDoc TRANSACTION = "transaction";
44     private final String JavaDoc PARAM = "param";
45     private final String JavaDoc DATEPARAM = "dateParam";
46
47     private final String JavaDoc JSP_TEXT = "jsp:text";
48
49     // attribute names
50
private final String JavaDoc SQL = "sql";
51     private final String JavaDoc DATASOURCE = "dataSource";
52
53
54     //*********************************************************************
55
// set its type and delegate validation to super-class
56
public ValidationMessage JavaDoc[] validate(
57         String JavaDoc prefix, String JavaDoc uri, PageData JavaDoc page) {
58     return super.validate( TYPE_SQL, prefix, uri, page );
59     }
60
61
62     //*********************************************************************
63
// Contract fulfillment
64

65     protected DefaultHandler JavaDoc getHandler() {
66     return new Handler JavaDoc();
67     }
68
69
70     //*********************************************************************
71
// SAX event handler
72

73     /** The handler that provides the base of our implementation. */
74     private class Handler extends DefaultHandler JavaDoc {
75
76     // parser state
77
private int depth = 0;
78         private Stack JavaDoc queryDepths = new Stack JavaDoc();
79         private Stack JavaDoc updateDepths = new Stack JavaDoc();
80         private Stack JavaDoc transactionDepths = new Stack JavaDoc();
81     private String JavaDoc lastElementName = null;
82     private boolean bodyNecessary = false;
83     private boolean bodyIllegal = false;
84
85     // process under the existing context (state), then modify it
86
public void startElement(
87             String JavaDoc ns, String JavaDoc ln, String JavaDoc qn, Attributes JavaDoc a) {
88
89         // substitute our own parsed 'ln' if it's not provided
90
if (ln == null)
91         ln = getLocalPart(qn);
92
93         // for simplicity, we can ignore <jsp:text> for our purposes
94
// (don't bother distinguishing between it and its characters)
95
if (qn.equals(JSP_TEXT))
96         return;
97
98         // check body-related constraint
99
if (bodyIllegal)
100         fail(Resources.getMessage("TLV_ILLEGAL_BODY", lastElementName));
101
102         // validate expression syntax if we need to
103
Set JavaDoc expAtts;
104         if (qn.startsWith(prefix + ":")
105             && (expAtts = (Set JavaDoc) config.get(ln)) != null) {
106         for (int i = 0; i < a.getLength(); i++) {
107             String JavaDoc attName = a.getLocalName(i);
108             if (expAtts.contains(attName)) {
109             String JavaDoc vMsg =
110                 validateExpression(
111                 ln,
112                 attName,
113                 a.getValue(i));
114             if (vMsg != null)
115                 fail(vMsg);
116             }
117         }
118         }
119
120             // validate attributes
121
if (qn.startsWith(prefix + ":") && !hasNoInvalidScope(a))
122                 fail(Resources.getMessage("TLV_INVALID_ATTRIBUTE",
123                     SCOPE, qn, a.getValue(SCOPE)));
124         if (qn.startsWith(prefix + ":") && hasEmptyVar(a))
125         fail(Resources.getMessage("TLV_EMPTY_VAR", qn));
126         if (qn.startsWith(prefix + ":") && hasDanglingScope(a) &&
127                 !qn.startsWith(prefix + ":" + SETDATASOURCE))
128         fail(Resources.getMessage("TLV_DANGLING_SCOPE", qn));
129
130         // now, modify state
131

132             /*
133              * Make sure <sql:param> is nested inside <sql:query> or
134              * <sql:update>. Note that <sql:param> does not need to
135              * be a direct child of <sql:query> or <sql:update>.
136              * Otherwise, the following would not work:
137              *
138              * <sql:query sql="..." var="...">
139              * <c:forEach var="arg" items="...">
140              * <sql:param value="${arg}"/>
141              * </c:forEach>
142              * </sql:query>
143              */

144             if ( (isSqlTag(ns, ln, PARAM) || isSqlTag(ns, ln, DATEPARAM))
145                 && (queryDepths.empty() && updateDepths.empty()) ) {
146                 fail(Resources.getMessage("SQL_PARAM_OUTSIDE_PARENT"));
147             }
148
149             // If we're in a <query>, record relevant state
150
if (isSqlTag(ns, ln, QUERY)) {
151                 queryDepths.push(new Integer JavaDoc(depth));
152             }
153             // If we're in a <update>, record relevant state
154
if (isSqlTag(ns, ln, UPDATE)) {
155                 updateDepths.push(new Integer JavaDoc(depth));
156             }
157             // If we're in a <transaction>, record relevant state
158
if (isSqlTag(ns, ln, TRANSACTION)) {
159                 transactionDepths.push(new Integer JavaDoc(depth));
160             }
161
162         // set up a check against illegal attribute/body combinations
163
bodyIllegal = false;
164         bodyNecessary = false;
165
166             if (isSqlTag(ns, ln, QUERY) || isSqlTag(ns, ln, UPDATE)) {
167                 if (!hasAttribute(a, SQL)) {
168                     bodyNecessary = true;
169                 }
170                 if (hasAttribute(a, DATASOURCE) && !transactionDepths.empty()) {
171                     fail(Resources.getMessage("ERROR_NESTED_DATASOURCE"));
172                 }
173             }
174
175             if (isSqlTag(ns, ln, DATEPARAM)) {
176                 bodyIllegal = true;
177             }
178
179         // record the most recent tag (for error reporting)
180
lastElementName = qn;
181         lastElementId = a.getValue("http://java.sun.com/JSP/Page", "id");
182
183         // we're a new element, so increase depth
184
depth++;
185     }
186
187     public void characters(char[] ch, int start, int length) {
188
189         bodyNecessary = false; // body is no longer necessary!
190

191         // ignore strings that are just whitespace
192
String JavaDoc s = new String JavaDoc(ch, start, length).trim();
193         if (s.equals(""))
194         return;
195
196         // check and update body-related constraints
197
if (bodyIllegal)
198         fail(Resources.getMessage("TLV_ILLEGAL_BODY", lastElementName));
199     }
200
201     public void endElement(String JavaDoc ns, String JavaDoc ln, String JavaDoc qn) {
202
203         // consistently, we ignore JSP_TEXT
204
if (qn.equals(JSP_TEXT))
205         return;
206
207         // handle body-related invariant
208
if (bodyNecessary)
209         fail(Resources.getMessage("TLV_MISSING_BODY",
210             lastElementName));
211         bodyIllegal = false; // reset: we've left the tag
212

213             // update <query>-related state
214
if (isSqlTag(ns, ln, QUERY)) {
215                 queryDepths.pop();
216             }
217             // update <update>-related state
218
if (isSqlTag(ns, ln, UPDATE)) {
219                 updateDepths.pop();
220             }
221             // update <update>-related state
222
if (isSqlTag(ns, ln, TRANSACTION)) {
223                 transactionDepths.pop();
224             }
225
226         // update our depth
227
depth--;
228     }
229     }
230 }
231
Popular Tags