1   /*
2    * Copyright 2002,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  package org.apache.commons.jelly.impl;
17  
18  import java.lang.ref.WeakReference;
19  import java.util.Iterator;
20  import java.util.List;
21  
22  import org.apache.commons.jelly.JellyContext;
23  import org.apache.commons.jelly.JellyException;
24  import org.apache.commons.jelly.JellyTagException;
25  import org.apache.commons.jelly.Script;
26  import org.apache.commons.jelly.XMLOutput;
27  import org.apache.commons.jelly.util.TagUtils;
28  
29  /*** Wraps another Script instance in a WeakReference. Used to prevent
30   * a Tag class from holding a hard reference to its body script.
31   * <p/>
32   * If the underlying Script has been GC'd and is no longer available,
33   * an exception is thrown on any attempt to use this Script.
34   * <p/>
35   * WARNING: This class is not a permanent part of the API and will be removed or replaced in a future release.
36   * Don't extend it or use it unless you absolutely must.
37   * 
38   * @author Hans Gilde
39   *
40   */
41  public class WeakReferenceWrapperScript implements Script {
42      private WeakReference reference;
43      
44      public WeakReferenceWrapperScript(Script script) {
45          reference = new WeakReference(script);
46      }
47      
48      /* (non-Javadoc)
49       * @see org.apache.commons.jelly.Script#compile()
50       */
51      public Script compile() throws JellyException {
52          return script().compile();
53      }
54  
55      /*** Use this method to access the script.
56       * @throws JellyException If the script has been GC'd.
57       */
58      public Script script() throws JellyTagException {
59          Script script = (Script) reference.get();
60          
61          if (script == null) {
62              throw new JellyTagException("Attempt to use a script that has been garbage collected.");
63          }
64          
65          return script;
66      }
67  
68      /* (non-Javadoc)
69       * @see org.apache.commons.jelly.Script#run(org.apache.commons.jelly.JellyContext, org.apache.commons.jelly.XMLOutput)
70       */
71      public void run(JellyContext context, XMLOutput output)
72              throws JellyTagException {
73          
74          script().run(context, output);
75      }
76      
77      /***Trims the white space from the script and its children.
78       * TODO this code should be refactored into a formal part of the Script interface.
79       * It has currently been cut and pasted from TagSupport.
80       */
81      public void trimWhitespace() throws JellyTagException {
82          TagUtils.trimScript(script());
83      }
84      
85      /*** Determines if this script (the one in the WeakReference) 
86       * or a child reference contains a Script
87       * that's of a particular class. 
88       * <p/>
89       * <strong>This method is in place
90       * to support specific features in the XML tag library and
91       * shouldn't be used by anyone at all.
92       * This method will be removed in a near-future verison of jelly.</strong>
93       * <p/>
94       * This method will be removed in a near-future verison of jelly.
95       * XXX this is totally bogus and temporary, we should not need to check the type of scripts.
96       * @param clazz Find a script that's an instance of this classs.
97       * @throws JellyTagException
98       */
99      public boolean containsScriptType(Class clazz) throws JellyTagException {
100         Object bodyScript = script();
101         
102         if (clazz.isInstance(bodyScript)) {
103             return true;
104         }
105         
106         if (bodyScript instanceof ScriptBlock) {
107             ScriptBlock scriptBlock = (ScriptBlock) bodyScript;
108             List scriptList = scriptBlock.getScriptList();
109             for (Iterator iter = scriptList.iterator(); iter.hasNext(); ) {
110                 Script script = (Script) iter.next();
111                 if (script instanceof StaticTagScript) {
112                     return true;
113                 }
114             }
115         }
116         
117         return false;
118     }
119     
120 }