001: /*
002: * Copyright 2004 Clinton Begin
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements;
017:
018: import java.io.PrintWriter;
019: import java.io.StringWriter;
020: import java.util.ArrayList;
021: import java.util.HashMap;
022: import java.util.LinkedList;
023: import java.util.List;
024:
025: import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMapping;
026:
027: public class SqlTagContext {
028:
029: private StringWriter sw;
030: private PrintWriter out;
031:
032: private HashMap attributes;
033:
034: private LinkedList removeFirstPrependStack;
035: private LinkedList iterateContextStack;
036:
037: private ArrayList parameterMappings = new ArrayList();
038:
039: public SqlTagContext() {
040: sw = new StringWriter();
041: out = new PrintWriter(sw);
042: attributes = new HashMap();
043: removeFirstPrependStack = new LinkedList();
044: iterateContextStack = new LinkedList();
045: }
046:
047: public PrintWriter getWriter() {
048: return out;
049: }
050:
051: public String getBodyText() {
052: out.flush();
053: return sw.getBuffer().toString();
054: }
055:
056: public void setAttribute(Object key, Object value) {
057: attributes.put(key, value);
058: }
059:
060: public Object getAttribute(Object key) {
061: return attributes.get(key);
062: }
063:
064: public void addParameterMapping(ParameterMapping mapping) {
065: parameterMappings.add(mapping);
066: }
067:
068: public List getParameterMappings() {
069: return parameterMappings;
070: }
071:
072: public boolean isEmptyRemoveFirtPrepend() {
073: return removeFirstPrependStack.size() <= 0;
074: }
075:
076: /**
077: * examine the value of the top RemoveFirstPrependMarker object on the stack.
078: *
079: * @return was the first prepend removed
080: */
081: public boolean peekRemoveFirstPrependMarker(SqlTag sqlTag) {
082:
083: RemoveFirstPrependMarker removeFirstPrepend = (RemoveFirstPrependMarker) removeFirstPrependStack
084: .get(1);
085:
086: return removeFirstPrepend.isRemoveFirstPrepend();
087: }
088:
089: /**
090: * pop the first RemoveFirstPrependMarker once the recursion is on it's way out
091: * of the recursion loop and return it's internal value.
092: *
093: * @param tag
094: */
095: public void popRemoveFirstPrependMarker(SqlTag tag) {
096:
097: RemoveFirstPrependMarker removeFirstPrepend = (RemoveFirstPrependMarker) removeFirstPrependStack
098: .getFirst();
099:
100: if (tag == removeFirstPrepend.getSqlTag()) {
101: removeFirstPrependStack.removeFirst();
102: }
103: }
104:
105: /**
106: * push a new RemoveFirstPrependMarker object with the specified internal state
107: *
108: * @param tag
109: */
110: public void pushRemoveFirstPrependMarker(SqlTag tag) {
111:
112: if (tag.getHandler() instanceof DynamicTagHandler) {
113: // this was added to retain default behavior
114: if (tag.isPrependAvailable()) {
115: removeFirstPrependStack
116: .addFirst(new RemoveFirstPrependMarker(tag,
117: true));
118: } else {
119: removeFirstPrependStack
120: .addFirst(new RemoveFirstPrependMarker(tag,
121: false));
122: }
123: } else if ("true".equals(tag.getRemoveFirstPrepend())
124: || "iterate".equals(tag.getRemoveFirstPrepend())) {
125: // you must be specific about the removal otherwise it
126: // will function as ibatis has always functioned and add
127: // the prepend
128: removeFirstPrependStack
129: .addFirst(new RemoveFirstPrependMarker(tag, true));
130: } else if (!tag.isPrependAvailable()
131: && !"true".equals(tag.getRemoveFirstPrepend())
132: && !"iterate".equals(tag.getRemoveFirstPrepend())
133: && tag.getParent() != null) {
134: // if no prepend or removeFirstPrepend is specified
135: // we need to look to the parent tag for default values
136: if ("true".equals(tag.getParent().getRemoveFirstPrepend())
137: || "iterate".equals(tag.getParent()
138: .getRemoveFirstPrepend())) {
139: removeFirstPrependStack
140: .addFirst(new RemoveFirstPrependMarker(tag,
141: true));
142: }
143: } else {
144: removeFirstPrependStack
145: .addFirst(new RemoveFirstPrependMarker(tag, false));
146: }
147:
148: }
149:
150: /**
151: * set a new internal state for top RemoveFirstPrependMarker object
152: *
153: */
154: public void disableRemoveFirstPrependMarker() {
155: ((RemoveFirstPrependMarker) removeFirstPrependStack.get(1))
156: .setRemoveFirstPrepend(false);
157: }
158:
159: public void reEnableRemoveFirstPrependMarker() {
160: ((RemoveFirstPrependMarker) removeFirstPrependStack.get(0))
161: .setRemoveFirstPrepend(true);
162: }
163:
164: /**
165: * iterate context is stored here for nested dynamic tags in
166: * the body of the iterate tag
167: *
168: * @param iterateContext
169: */
170: public void pushIterateContext(IterateContext iterateContext) {
171: iterateContextStack.addFirst(iterateContext);
172: }
173:
174: /**
175: * iterate context is removed here from the stack when iterate tag is finished being
176: * processed
177: *
178: * @return the top element of the context stack
179: */
180: public IterateContext popIterateContext() {
181: IterateContext retVal = null;
182: if (!iterateContextStack.isEmpty()) {
183: retVal = (IterateContext) iterateContextStack.removeFirst();
184: }
185: return retVal;
186: }
187:
188: /**
189: * iterate context is removed here from the stack when iterate tag is finished being
190: * processed
191: *
192: * @return the top element on the context stack
193: */
194: public IterateContext peekIterateContext() {
195: IterateContext retVal = null;
196: if (!iterateContextStack.isEmpty()) {
197: retVal = (IterateContext) iterateContextStack.getFirst();
198: }
199: return retVal;
200: }
201:
202: }
203:
204: /**
205: *
206: * This inner class i used strictly to house whether the
207: * removeFirstPrepend has been used in a particular nested
208: * situation.
209: *
210: * @author Brandon Goodin
211: */
212: class RemoveFirstPrependMarker {
213:
214: private boolean removeFirstPrepend;
215: private SqlTag tag;
216:
217: /**
218: *
219: */
220: public RemoveFirstPrependMarker(SqlTag tag,
221: boolean removeFirstPrepend) {
222: this .removeFirstPrepend = removeFirstPrepend;
223: this .tag = tag;
224: }
225:
226: /**
227: * @return Returns the removeFirstPrepend.
228: */
229: public boolean isRemoveFirstPrepend() {
230: return removeFirstPrepend;
231: }
232:
233: /**
234: * @param removeFirstPrepend The removeFirstPrepend to set.
235: */
236: public void setRemoveFirstPrepend(boolean removeFirstPrepend) {
237: this .removeFirstPrepend = removeFirstPrepend;
238: }
239:
240: /**
241: * @return Returns the sqlTag.
242: */
243: public SqlTag getSqlTag() {
244: return tag;
245: }
246:
247: }
|