1 package org.kohsuke.stapler; 2 3 import org.apache.commons.jelly.Script; 4 import org.kohsuke.stapler.jelly.JellyClassTearOff; 5 import org.kohsuke.stapler.jelly.groovy.GroovyClassTearOff; 6 7 import javax.servlet.RequestDispatcher ; 8 import javax.servlet.ServletException ; 9 import java.io.IOException ; 10 import java.lang.reflect.Field ; 11 import java.lang.reflect.InvocationTargetException ; 12 import java.util.ArrayList ; 13 import java.util.List ; 14 import java.util.Map ; 15 import java.util.WeakHashMap ; 16 17 23 public class MetaClass extends TearOffSupport { 24 27 public final Class clazz; 28 29 33 public final MetaClassLoader classLoader; 34 35 public final List <Dispatcher> dispatchers = new ArrayList <Dispatcher>(); 36 37 41 public final MetaClass baseClass; 42 43 private MetaClass(Class clazz) { 44 this.clazz = clazz; 45 this.baseClass = get(clazz.getSuperclass()); 46 this.classLoader = MetaClassLoader.get(clazz.getClassLoader()); 47 48 buildDispatchers( 49 new ClassDescriptor(clazz,null)); 50 } 51 52 53 private void buildDispatchers( ClassDescriptor node ) { 54 for( final Function f : node.methods.prefix("do").signature(StaplerRequest.class,StaplerResponse.class) ) { 56 String name = camelize(f.getName().substring(2)); dispatchers.add(new NameBasedDispatcher(name,0) { 58 public void doDispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IllegalAccessException , InvocationTargetException { 59 f.invoke(req, node,req,rsp); 60 } 61 }); 62 } 63 64 dispatchers.add(new Dispatcher() { 65 public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException , ServletException { 66 String next = req.tokens.peek(); 71 if(next==null) return false; 72 73 Stapler stapler = req.getStapler(); 74 75 RequestDispatcher disp = stapler.getResourceDispatcher(node,next+".jsp"); 76 if(disp==null) return false; 77 78 req.tokens.next(); 79 stapler.forward(disp,req,rsp); 80 return true; 81 } 82 }); 83 84 try { 85 dispatchers.add(new Dispatcher() { 86 final JellyClassTearOff tearOff = loadTearOff(JellyClassTearOff.class); 87 88 public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException , ServletException { 89 String next = req.tokens.peek(); 91 if(next==null) return false; 92 93 try { 94 Script script = tearOff.findScript(next+".jelly"); 95 96 if(script==null) return false; 98 req.tokens.next(); 99 100 JellyClassTearOff.invokeScript(req, rsp, script, node); 101 102 return true; 103 } catch (RuntimeException e) { 104 throw e; 105 } catch (IOException e) { 106 throw e; 107 } catch (Exception e) { 108 throw new ServletException (e); 109 } 110 } 111 }); 112 } catch (LinkageError e) { 113 } 115 116 try { 117 dispatchers.add(new Dispatcher() { 118 final GroovyClassTearOff tearOff = loadTearOff(GroovyClassTearOff.class); 119 120 public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException , ServletException { 121 String next = req.tokens.peek(); 123 if(next==null) return false; 124 125 try { 126 Script script = tearOff.findScript(next+".groovy"); 127 if(script==null) return false; 129 req.tokens.next(); 130 131 JellyClassTearOff.invokeScript(req, rsp, script, node); 132 133 return true; 134 } catch (RuntimeException e) { 135 throw e; 136 } catch (IOException e) { 137 throw e; 138 } catch (Exception e) { 139 throw new ServletException (e); 140 } 141 } 142 }); 143 } catch (LinkageError e) { 144 } 146 147 for( final Function f : node.methods 149 .signature(StaplerRequest.class,StaplerResponse.class) 150 .name("doIndex") ) { 151 152 dispatchers.add(new Dispatcher() { 153 public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IllegalAccessException , InvocationTargetException { 154 if(req.tokens.hasMore()) 155 return false; f.invoke(req,node,req,rsp); 157 return true; 158 } 159 }); 160 } 161 162 for (final Field f : node.fields) { 164 dispatchers.add(new NameBasedDispatcher(f.getName()) { 165 final String role = getProtectedRole(f); 166 public void doDispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException , ServletException , IllegalAccessException { 167 if(role!=null && !req.isUserInRole(role)) 168 throw new IllegalAccessException ("Needs to be in role "+role); 169 req.getStapler().invoke(req, rsp, f.get(node)); 170 } 171 }); 172 } 173 174 FunctionList getMethods = node.methods.prefix("get"); 175 176 for( final Function f : getMethods.signature() ) { 178 if(f.getName().length()<=3) 179 continue; 180 String name = camelize(f.getName().substring(3)); dispatchers.add(new NameBasedDispatcher(name) { 182 public void doDispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException , ServletException , IllegalAccessException , InvocationTargetException { 183 req.getStapler().invoke(req,rsp,f.invoke(req, node)); 184 } 185 }); 186 } 187 188 for( final Function f : getMethods.signature(StaplerRequest.class) ) { 190 if(f.getName().length()<=3) 191 continue; 192 String name = camelize(f.getName().substring(3)); dispatchers.add(new NameBasedDispatcher(name) { 194 public void doDispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException , ServletException , IllegalAccessException , InvocationTargetException { 195 req.getStapler().invoke(req,rsp,f.invoke(req, node,req)); 196 } 197 }); 198 } 199 200 for( final Function f : getMethods.signature(String .class) ) { 202 if(f.getName().length()<=3) 203 continue; 204 String name = camelize(f.getName().substring(3)); dispatchers.add(new NameBasedDispatcher(name,1) { 206 public void doDispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException , ServletException , IllegalAccessException , InvocationTargetException { 207 req.getStapler().invoke(req,rsp,f.invoke(req, node,req.tokens.next())); 208 } 209 }); 210 } 211 212 for( final Function f : getMethods.signature(int.class) ) { 214 if(f.getName().length()<=3) 215 continue; 216 String name = camelize(f.getName().substring(3)); dispatchers.add(new NameBasedDispatcher(name,1) { 218 public void doDispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException , ServletException , IllegalAccessException , InvocationTargetException { 219 int idx = Integer.valueOf(req.tokens.next()); 220 req.getStapler().invoke(req,rsp,f.invoke(req, node,idx)); 221 } 222 }); 223 } 224 225 if(node.clazz.isArray()) { 226 dispatchers.add(new Dispatcher() { 227 public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException , ServletException { 228 if(!req.tokens.hasMore()) 229 return false; 230 try { 231 req.getStapler().invoke(req,rsp,((Object [])node)[req.tokens.nextAsInt()]); 232 return true; 233 } catch (NumberFormatException e) { 234 return false; } 236 } 237 }); 238 } 239 240 if(List .class.isAssignableFrom(node.clazz)) { 241 dispatchers.add(new Dispatcher() { 242 public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException , ServletException { 243 if(!req.tokens.hasMore()) 244 return false; 245 try { 246 req.getStapler().invoke(req,rsp,((List )node).get(req.tokens.nextAsInt())); 247 return true; 248 } catch (NumberFormatException e) { 249 return false; } 251 } 252 }); 253 } 254 255 if(Map .class.isAssignableFrom(node.clazz)) { 256 dispatchers.add(new Dispatcher() { 257 public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException , ServletException { 258 if(!req.tokens.hasMore()) 259 return false; 260 try { 261 Object item = ((Map )node).get(req.tokens.peek()); 262 if(item!=null) { 263 req.tokens.next(); 264 req.getStapler().invoke(req,rsp,item); 265 return true; 266 } else { 267 return false; 269 } 270 } catch (NumberFormatException e) { 271 return false; } 273 } 274 }); 275 } 276 277 280 for( final Function f : node.methods 282 .signature(StaplerRequest.class,StaplerResponse.class) 283 .name("doDynamic") ) { 284 285 dispatchers.add(new Dispatcher() { 286 public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IllegalAccessException , InvocationTargetException { 287 f.invoke(req,node,req,rsp); 288 return true; 289 } 290 }); 291 } 292 293 for( final Function f : getMethods.signature(String .class,StaplerRequest.class,StaplerResponse.class).name("getDynamic")) { 295 dispatchers.add(new Dispatcher() { 296 public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IllegalAccessException , InvocationTargetException , IOException , ServletException { 297 if(!req.tokens.hasMore()) 298 return false; 299 String token = req.tokens.next(); 300 req.getStapler().invoke(req,rsp,f.invoke(req,node,token,req,rsp)); 301 return true; 302 } 303 }); 304 } 305 } 306 307 private String getProtectedRole(Field f) { 308 try { 309 LimitedTo a = f.getAnnotation(LimitedTo.class); 310 return (a!=null)?a.value():null; 311 } catch (LinkageError e) { 312 return null; } 314 } 315 316 private static String camelize(String name) { 317 return Character.toLowerCase(name.charAt(0))+name.substring(1); 318 } 319 320 324 public static boolean NO_CACHE = false; 325 326 static { 327 try { 328 NO_CACHE = Boolean.getBoolean("stapler.jelly.noCache"); 329 } catch (SecurityException e) { 330 } 332 } 333 334 335 336 public static MetaClass get(Class c) { 337 if(c==null) return null; 338 synchronized(classMap) { 339 MetaClass mc = classMap.get(c); 340 if(mc==null) { 341 mc = new MetaClass(c); 342 classMap.put(c,mc); 343 } 344 return mc; 345 } 346 } 347 348 353 private static final Map <Class ,MetaClass> classMap = new WeakHashMap <Class ,MetaClass>(); 354 } 355 | Popular Tags |