KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > kohsuke > stapler > jelly > groovy > JellyBuilder


1 package org.kohsuke.stapler.jelly.groovy;
2
3 import groovy.lang.Closure;
4 import groovy.lang.GroovyObjectSupport;
5 import groovy.lang.MissingMethodException;
6 import groovy.xml.QName;
7 import org.apache.commons.beanutils.ConvertingWrapDynaBean;
8 import org.apache.commons.beanutils.DynaBean;
9 import org.apache.commons.beanutils.DynaProperty;
10 import org.apache.commons.jelly.DynaTag;
11 import org.apache.commons.jelly.JellyContext;
12 import org.apache.commons.jelly.JellyException;
13 import org.apache.commons.jelly.JellyTagException;
14 import org.apache.commons.jelly.Script;
15 import org.apache.commons.jelly.Tag;
16 import org.apache.commons.jelly.TagLibrary;
17 import org.apache.commons.jelly.TagSupport;
18 import org.apache.commons.jelly.XMLOutput;
19 import org.apache.commons.jelly.expression.Expression;
20 import org.apache.commons.jelly.expression.ConstantExpression;
21 import org.apache.commons.jelly.impl.TextScript;
22 import org.codehaus.groovy.runtime.InvokerHelper;
23 import org.xml.sax.Attributes JavaDoc;
24 import org.xml.sax.SAXException JavaDoc;
25 import org.xml.sax.helpers.AttributesImpl JavaDoc;
26
27 import java.util.Collections JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.Map.Entry;
31
32 /**
33  * Drive Jelly scripts from Groovy markup.
34  *
35  * @author Kohsuke Kawaguchi
36  */

37 public final class JellyBuilder extends GroovyObjectSupport {
38     /**
39      * Current {@link XMLOutput}.
40      */

41     private XMLOutput output;
42
43     /**
44      * Current {@link Tag} in which we are executing.
45      */

46     private Tag current;
47
48     private JellyContext context;
49
50     public JellyBuilder(JellyContext context,XMLOutput output) {
51         this.context = context;
52         this.output = output;
53     }
54
55     /**
56      * This is used to allow QName to be used for the invocation.
57      */

58     public Namespace namespace(String JavaDoc nsUri, String JavaDoc prefix) {
59         return new Namespace(this,nsUri,prefix);
60     }
61
62     public Namespace namespace(String JavaDoc nsUri) {
63         return namespace(nsUri,null);
64     }
65
66     @Override JavaDoc
67     public Object JavaDoc invokeMethod(String JavaDoc name, Object JavaDoc args) {
68         doInvokeMethod(new QName("",name), args);
69         return null;
70     }
71
72     @SuppressWarnings JavaDoc({"ChainOfInstanceofChecks"})
73     protected void doInvokeMethod(QName name, Object JavaDoc args) {
74         List JavaDoc list = InvokerHelper.asList(args);
75
76         Map JavaDoc attributes = Collections.EMPTY_MAP;
77         Closure closure = null;
78         String JavaDoc innerText = null;
79
80         // figure out what parameters are what
81
switch (list.size()) {
82         case 0:
83             break;
84         case 1: {
85             Object JavaDoc object = list.get(0);
86             if (object instanceof Map JavaDoc) {
87                 attributes = (Map JavaDoc) object;
88             } else if (object instanceof Closure) {
89                 closure = (Closure) object;
90                 break;
91             } else {
92                 innerText = object.toString();
93             }
94             break;
95         }
96         case 2: {
97             Object JavaDoc object1 = list.get(0);
98             Object JavaDoc object2 = list.get(1);
99             if (object1 instanceof Map JavaDoc) {
100                 attributes = (Map JavaDoc) object1;
101                 if (object2 instanceof Closure) {
102                     closure = (Closure) object2;
103                 } else {
104                     innerText = object2.toString();
105                 }
106             } else {
107                 innerText = object1.toString();
108                 if (object2 instanceof Closure) {
109                     closure = (Closure) object2;
110                 } else if (object2 instanceof Map JavaDoc) {
111                     attributes = (Map JavaDoc) object2;
112                 } else {
113                     throw new MissingMethodException(name.toString(), getClass(), list.toArray());
114                 }
115             }
116             break;
117         }
118         case 3: {
119             Object JavaDoc arg0 = list.get(0);
120             Object JavaDoc arg1 = list.get(1);
121             Object JavaDoc arg2 = list.get(2);
122             if (arg0 instanceof Map JavaDoc && arg2 instanceof Closure) {
123                 closure = (Closure) arg2;
124                 attributes = (Map JavaDoc) arg0;
125                 innerText = arg1.toString();
126             } else if (arg1 instanceof Map JavaDoc && arg2 instanceof Closure) {
127                 closure = (Closure) arg2;
128                 attributes = (Map JavaDoc) arg1;
129                 innerText = arg0.toString();
130             } else {
131                 throw new MissingMethodException(name.toString(), getClass(), list.toArray());
132             }
133             break;
134         }
135         default:
136             throw new MissingMethodException(name.toString(), getClass(), list.toArray());
137         }
138
139         Tag parent = current;
140
141         try {
142             Tag t = createTag(name,attributes);
143             if (parent != null)
144                 t.setParent(parent);
145             t.setContext(context);
146             if(closure!=null)
147                 t.setBody(new ClosureScript(this,closure));
148             else
149             if(innerText!=null)
150                 t.setBody(new TextScript(innerText));
151             else
152                 t.setBody(NULL_SCRIPT);
153
154             current = t;
155
156             t.doTag(output);
157         } catch(JellyException e) {
158             throw new RuntimeException JavaDoc(e); // what's the proper way to handle exceptions in Groovy?
159
} finally {
160             current = parent;
161         }
162     }
163
164     private Tag createTag(final QName n, final Map JavaDoc attributes) throws JellyException {
165         TagLibrary lib = context.getTagLibrary(n.getNamespaceURI());
166         if(lib!=null) {
167             Tag t = lib.createTag(n.getLocalPart(), toAttributes(attributes));
168             if(t!=null) {
169                 configureTag(t,attributes);
170                 return t;
171             }
172         }
173
174         // otherwise treat it as a literal.
175
return new TagSupport() {
176             public void doTag(XMLOutput output) throws JellyTagException {
177                 try {
178                     List JavaDoc<Namespace> nsList = (List JavaDoc<Namespace>)InvokerHelper.asList(attributes.get("xmlns"));
179                     if(nsList!=null) {
180                         for (Namespace ns : nsList)
181                             ns.startPrefixMapping(output);
182                     }
183
184                     output.startElement(n.getNamespaceURI(), n.getLocalPart(), n.getQualifiedName(), toAttributes(attributes));
185                     invokeBody(output);
186                     output.endElement(n.getNamespaceURI(), n.getLocalPart(), n.getQualifiedName());
187
188                     if(nsList!=null) {
189                         for (Namespace ns : nsList)
190                             ns.endPrefixMapping(output);
191                     }
192                 } catch (SAXException JavaDoc e) {
193                     throw new JellyTagException(e);
194                 }
195             }
196         };
197     }
198
199     /*
200      * Copyright 2002,2004 The Apache Software Foundation.
201      *
202      * Licensed under the Apache License, Version 2.0 (the "License");
203      * you may not use this file except in compliance with the License.
204      * You may obtain a copy of the License at
205      *
206      * http://www.apache.org/licenses/LICENSE-2.0
207      *
208      * Unless required by applicable law or agreed to in writing, software
209      * distributed under the License is distributed on an "AS IS" BASIS,
210      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
211      * See the License for the specific language governing permissions and
212      * limitations under the License.
213      */

214     private void configureTag(Tag tag, Map JavaDoc attributes) throws JellyException {
215         if ( tag instanceof DynaTag ) {
216             DynaTag dynaTag = (DynaTag) tag;
217
218             for (Object JavaDoc o : attributes.entrySet()) {
219                 Entry entry = (Entry) o;
220                 String JavaDoc name = (String JavaDoc) entry.getKey();
221                 if(name.equals("xmlns")) continue; // we'll process this by ourselves
222

223
224                 Object JavaDoc value = getValue(entry, dynaTag.getAttributeType(name));
225                 dynaTag.setAttribute(name, value);
226             }
227         } else {
228             // treat the tag as a bean
229
DynaBean dynaBean = new ConvertingWrapDynaBean( tag );
230             for (Object JavaDoc o : attributes.entrySet()) {
231                 Entry entry = (Entry) o;
232                 String JavaDoc name = (String JavaDoc) entry.getKey();
233                 if(name.equals("xmlns")) continue; // we'll process this by ourselves
234

235                 DynaProperty property = dynaBean.getDynaClass().getDynaProperty(name);
236                 if (property == null) {
237                     throw new JellyException("This tag does not understand the '" + name + "' attribute");
238                 }
239
240                 dynaBean.set(name, getValue(entry,property.getType()));
241             }
242         }
243     }
244
245     /**
246      * Obtains the value from the map entry in the right type.
247      */

248     private Object JavaDoc getValue(Entry entry, Class JavaDoc type) {
249         Object JavaDoc value = entry.getValue();
250         if (type== Expression.class)
251             value = new ConstantExpression(entry.getValue());
252         return value;
253     }
254
255     private Attributes JavaDoc toAttributes(Map JavaDoc attributes) {
256         AttributesImpl JavaDoc atts = new AttributesImpl JavaDoc();
257         for (Object JavaDoc o : attributes.entrySet()) {
258             Entry e = (Entry) o;
259             if(e.getKey().toString().equals("xmlns")) continue; // we'll process them outside attributes
260
atts.addAttribute("", e.getKey().toString(), e.getKey().toString(), null, e.getValue().toString());
261         }
262         return atts;
263     }
264
265
266     JellyContext setContext(JellyContext newValue) {
267         JellyContext old = context;
268         context = newValue;
269         return old;
270     }
271
272     public XMLOutput setOutput(XMLOutput newValue) {
273         XMLOutput old = output;
274         output = newValue;
275         return old;
276     }
277
278     /**
279      * {@link Script} that does nothing.
280      */

281     private static final Script NULL_SCRIPT = new Script() {
282         public Script compile() {
283             return this;
284         }
285
286         public void run(JellyContext context, XMLOutput output) {
287         }
288     };
289 }
290
Popular Tags