| 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 ; 24 import org.xml.sax.SAXException ; 25 import org.xml.sax.helpers.AttributesImpl ; 26 27 import java.util.Collections ; 28 import java.util.List ; 29 import java.util.Map ; 30 import java.util.Map.Entry; 31 32 37 public final class JellyBuilder extends GroovyObjectSupport { 38 41 private XMLOutput output; 42 43 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 58 public Namespace namespace(String nsUri, String prefix) { 59 return new Namespace(this,nsUri,prefix); 60 } 61 62 public Namespace namespace(String nsUri) { 63 return namespace(nsUri,null); 64 } 65 66 @Override  67 public Object invokeMethod(String name, Object args) { 68 doInvokeMethod(new QName("",name), args); 69 return null; 70 } 71 72 @SuppressWarnings ({"ChainOfInstanceofChecks"}) 73 protected void doInvokeMethod(QName name, Object args) { 74 List list = InvokerHelper.asList(args); 75 76 Map attributes = Collections.EMPTY_MAP; 77 Closure closure = null; 78 String innerText = null; 79 80 switch (list.size()) { 82 case 0: 83 break; 84 case 1: { 85 Object object = list.get(0); 86 if (object instanceof Map ) { 87 attributes = (Map ) 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 object1 = list.get(0); 98 Object object2 = list.get(1); 99 if (object1 instanceof Map ) { 100 attributes = (Map ) 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 ) { 111 attributes = (Map ) object2; 112 } else { 113 throw new MissingMethodException(name.toString(), getClass(), list.toArray()); 114 } 115 } 116 break; 117 } 118 case 3: { 119 Object arg0 = list.get(0); 120 Object arg1 = list.get(1); 121 Object arg2 = list.get(2); 122 if (arg0 instanceof Map && arg2 instanceof Closure) { 123 closure = (Closure) arg2; 124 attributes = (Map ) arg0; 125 innerText = arg1.toString(); 126 } else if (arg1 instanceof Map && arg2 instanceof Closure) { 127 closure = (Closure) arg2; 128 attributes = (Map ) 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 (e); } finally { 160 current = parent; 161 } 162 } 163 164 private Tag createTag(final QName n, final Map 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 return new TagSupport() { 176 public void doTag(XMLOutput output) throws JellyTagException { 177 try { 178 List <Namespace> nsList = (List <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 e) { 193 throw new JellyTagException(e); 194 } 195 } 196 }; 197 } 198 199 214 private void configureTag(Tag tag, Map attributes) throws JellyException { 215 if ( tag instanceof DynaTag ) { 216 DynaTag dynaTag = (DynaTag) tag; 217 218 for (Object o : attributes.entrySet()) { 219 Entry entry = (Entry) o; 220 String name = (String ) entry.getKey(); 221 if(name.equals("xmlns")) continue; 223 224 Object value = getValue(entry, dynaTag.getAttributeType(name)); 225 dynaTag.setAttribute(name, value); 226 } 227 } else { 228 DynaBean dynaBean = new ConvertingWrapDynaBean( tag ); 230 for (Object o : attributes.entrySet()) { 231 Entry entry = (Entry) o; 232 String name = (String ) entry.getKey(); 233 if(name.equals("xmlns")) continue; 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 248 private Object getValue(Entry entry, Class type) { 249 Object value = entry.getValue(); 250 if (type== Expression.class) 251 value = new ConstantExpression(entry.getValue()); 252 return value; 253 } 254 255 private Attributes toAttributes(Map attributes) { 256 AttributesImpl atts = new AttributesImpl (); 257 for (Object o : attributes.entrySet()) { 258 Entry e = (Entry) o; 259 if(e.getKey().toString().equals("xmlns")) continue; 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 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 |