KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > taglibs > xtags > xpath > StylesheetTag


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.xtags.xpath;
18
19
20
21 import java.io.ByteArrayInputStream JavaDoc;
22 import java.io.ByteArrayOutputStream JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.io.OutputStream JavaDoc;
25 import java.io.IOException JavaDoc;
26
27 import java.util.Iterator JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Stack JavaDoc;
30 import java.util.ArrayList JavaDoc;
31
32 import javax.servlet.ServletContext JavaDoc;
33 import javax.servlet.jsp.JspException JavaDoc;
34 import javax.servlet.jsp.JspWriter JavaDoc;
35 import javax.servlet.jsp.PageContext JavaDoc;
36 import javax.servlet.jsp.tagext.BodyTagSupport JavaDoc;
37
38 import org.dom4j.DocumentException;
39 import org.dom4j.InvalidXPathException;
40 import org.dom4j.Node;
41 import org.dom4j.XPath;
42 import org.dom4j.DocumentFactory;
43 import org.dom4j.DocumentHelper;
44 import org.dom4j.rule.Action;
45 import org.dom4j.rule.Rule;
46 import org.dom4j.rule.Stylesheet;
47
48 import org.apache.taglibs.xtags.util.JspVariableContext;
49
50 /** The body of this tag defines a stylesheet which is implemented via calling
51   * a JSP include.
52   *
53   * @author James Strachan
54   */

55 public class StylesheetTag extends AbstractBodyTag {
56
57     /** Holds the stylesheet which will be applied to the source context. */
58     private Stylesheet stylesheet = new Stylesheet();
59     
60     /** Holds value of property mode. */
61     private String JavaDoc mode;
62
63     /** Previous value of Stylesheet if nesting of stylesheet occurs */
64     private Stylesheet previousStylesheet;
65     
66     /** The default action used to specify the value of a node */
67     
68     private Action valueOfAction;
69     
70     private Stack JavaDoc templateResultLists = new Stack JavaDoc();
71     private Stack JavaDoc resultIterators = new Stack JavaDoc();
72     
73     private List JavaDoc openResultList;
74     
75     private int currentState;
76     private TemplateExecution currentMatch;
77     private StringBuffer JavaDoc avtOutput = new StringBuffer JavaDoc(256);
78     private StringBuffer JavaDoc actionOutput = new StringBuffer JavaDoc(2048);
79     
80     static final int INITIALISE_STYLESHEET = 1;
81     static final int RUN_TEMPLATES = 2;
82     
83     protected Object JavaDoc context;
84         
85     public StylesheetTag() {
86         // add default actions
87
valueOfAction = new StylesheetValueOfAction(this);
88         stylesheet.setValueOfAction( valueOfAction );
89     }
90
91     public Stylesheet getStylesheet() {
92         return stylesheet;
93     }
94     
95     public void addTemplate( Rule rule ) {
96         stylesheet.addRule( rule );
97     }
98
99     int getCurrentState() {
100         return this.currentState;
101     }
102     
103     
104     // Tag interface
105
//-------------------------------------------------------------------------
106
public void setPageContext(PageContext JavaDoc pageContext) {
107         super.setPageContext(pageContext);
108     }
109     
110     public int doStartTag() throws JspException JavaDoc {
111         previousStylesheet = TagHelper.getStylesheet( pageContext );
112         TagHelper.setStylesheet( pageContext, stylesheet );
113         stylesheet.clear();
114         templateResultLists.clear();
115         actionOutput.delete(0, actionOutput.length() );
116         
117         currentState = INITIALISE_STYLESHEET;
118         
119         return EVAL_BODY_TAG;
120     }
121
122     public int doAfterBody() throws JspException JavaDoc {
123         try {
124             if (currentState == INITIALISE_STYLESHEET) {
125                 // Need to run the stylesheet
126
runStylesheet();
127
128                 currentState = RUN_TEMPLATES;
129             } else {
130                 // Make sure that any text in the output gets pushed into the result
131
// list - this is necessary if the last action was not a template execution
132
addOutputToResultList();
133                 // Get rid of the writespace between the templates.
134
bodyContent.clear();
135             }
136             
137             if (this.openResultList != null) {
138                 // Need suspend processing the current result list, and start on this one...
139
this.templateResultLists.push(this.openResultList);
140                 this.resultIterators.push( this.openResultList.iterator() );
141                 this.openResultList = null;
142             }
143                 
144             return processResults();
145         } catch (Exception JavaDoc e) {
146             handleException(e);
147         }
148         return SKIP_BODY;
149     }
150
151     public int doEndTag() throws JspException JavaDoc {
152         // restore the previous stylesheet value
153
TagHelper.setStylesheet( pageContext, previousStylesheet );
154         reset();
155         return EVAL_PAGE;
156     }
157
158     public void runStylesheet() throws Exception JavaDoc {
159         stylesheet.setModeName( getMode() );
160         stylesheet.run( getInputNodes() );
161     }
162     
163     /** This method is called once the stylesheet has been run, and the list of output strings
164      * and template executions has been collated. Each string in the list is output to the
165      * BodyContent's writer, and whenever a template body needs to be run, the StylesheetTag will
166      * evaluate its body again evaluating the correct TemplateTag body. Then it resumes processing
167      * of the outputs and so on until the list is exhausted.
168      */

169     int processResults() throws IOException JavaDoc {
170         while (! this.resultIterators.isEmpty()) {
171             Iterator JavaDoc resultIter = (Iterator JavaDoc)this.resultIterators.peek();
172             while (resultIter.hasNext()) {
173                 Object JavaDoc o = resultIter.next();
174                 if (o instanceof String JavaDoc) {
175                     bodyContent.getEnclosingWriter().write( (String JavaDoc)o );
176                 } else{
177                     currentMatch = (TemplateExecution)o;
178                     return EVAL_BODY_TAG;
179                 }
180             }
181             this.resultIterators.pop();
182             this.templateResultLists.pop();
183         }
184         return SKIP_BODY;
185     }
186
187     /** TemplateTag objects call this method to see if they should run their template
188      * bodies. If the template matches the first on our "execution list", then it should
189      * run.
190      * @returns a TemplateExecution object that tells the template which node to use as the
191      * context for its evaluation. This was recorded when the XLST action created the
192      * TemplateExecution object (see {@link BodyAction}). <br>
193      * -or-<br>
194      * <code>null</code> to tell the template body NOT to evaluate its body.
195      */

196     TemplateExecution getTemplateExecution(String JavaDoc match) {
197         if (currentMatch.getMatch().equals(match)) {
198             return currentMatch;
199         } else {
200             return null;
201         }
202     }
203     
204     public void release() {
205         super.release();
206         reset();
207     }
208
209     void reset() {
210         stylesheet.clear();
211         openResultList = null;
212         currentMatch = null;
213         templateResultLists.clear();
214         resultIterators.clear();
215         actionOutput.delete(0, actionOutput.length() );
216         avtOutput.delete(0, actionOutput.length() );
217     }
218     // Properties
219
//-------------------------------------------------------------------------
220

221     /** Getter for property mode.
222      * @return Value of property mode.
223      */

224     public String JavaDoc getMode() {
225         return mode;
226     }
227     
228     /** Setter for property mode.
229      * @param mode New value of property mode.
230      */

231     public void setMode(String JavaDoc mode) {
232         this.mode = mode;
233     }
234     
235     /* Adds a string into the output of the stylesheet.
236      */

237     void addOutput(String JavaDoc text){
238         actionOutput.append(text);
239     }
240
241     void addOutputToResultList() {
242         if (actionOutput.length() > 0) {
243             getOpenResultList().add( actionOutput.toString() );
244             actionOutput.delete(0, actionOutput.length() );
245         }
246     }
247     
248     /**
249      * Adds a request to execute a Stylesheet's template body.
250      * Called by the XSLT template's Action when it matches such
251      * a template rule.
252      */

253     void addTemplateExecution(TemplateExecution te) {
254         // Add any text in the actionOutput to the result list, before we add
255
// the TemplateExecution
256
addOutputToResultList();
257         getOpenResultList().add(te);
258     }
259     
260     List JavaDoc getOpenResultList() {
261         if (this.openResultList == null) {
262             this.openResultList = new ArrayList JavaDoc(256);
263         }
264         return this.openResultList;
265     }
266
267     String JavaDoc processAVTs(String JavaDoc text) throws IOException JavaDoc, InvalidXPathException {
268         int marker = 0;
269         int leftBracket;
270         int rightBracket;
271         XPath xpath;
272         Object JavaDoc context = getInputNodes();
273         
274         avtOutput.delete(0, avtOutput.length() );
275
276         while ( (leftBracket = text.indexOf('{', marker)) > 0) {
277             // output all text up to the {
278
avtOutput.append(text.substring(marker,leftBracket));
279             rightBracket = text.indexOf('}', leftBracket);
280             if (rightBracket < 0) {
281                 marker = leftBracket; // It's not part of an xpath expression
282
// No more valid {xpath} expressions
283
break;
284             }
285             xpath = createXPath( text.substring(leftBracket+1, rightBracket) );
286             if (xpath == null) {
287                 throw new InvalidXPathException( text.substring(leftBracket+1, rightBracket) );
288             }
289             avtOutput.append( xpath.valueOf( context ) );
290             marker = rightBracket+1;
291         }
292         if (marker < text.length()) {
293             avtOutput.append( text.substring(marker) );
294         }
295         
296         return avtOutput.toString();
297     }
298     
299     
300     
301     
302     /** @return the input node on which to make a selction
303       */

304     public Object JavaDoc getInputNodes() {
305         if ( context == null ) {
306             return TagHelper.getInputNodes( pageContext, this, true );
307         }
308         return context;
309     }
310     
311     /** A factory method to create new XPath instances */
312     protected XPath createXPath(String JavaDoc xpathExpression) {
313         XPath xpath = getDocumentFactory().createXPath( xpathExpression );
314         xpath.setVariableContext( JspVariableContext.getInstance( pageContext ) );
315         return xpath;
316     }
317
318     /** @return the factory used to create XPath instances */
319     protected DocumentFactory getDocumentFactory() {
320         return DocumentFactory.getInstance();
321     }
322
323     public void setContext(Object JavaDoc context) {
324         this.context = context;
325     }
326 }
327
Popular Tags