1 52 53 package freemarker.ext.jython; 54 55 import java.math.BigDecimal ; 56 import java.math.BigInteger ; 57 import java.util.ArrayList ; 58 import java.util.Collection ; 59 import java.util.List ; 60 import java.util.Map ; 61 62 import org.python.core.Py; 63 import org.python.core.PyDictionary; 64 import org.python.core.PyFloat; 65 import org.python.core.PyInteger; 66 import org.python.core.PyJavaInstance; 67 import org.python.core.PyLong; 68 import org.python.core.PyNone; 69 import org.python.core.PyObject; 70 import org.python.core.PySequence; 71 import org.python.core.PyString; 72 import org.python.core.PyStringMap; 73 74 import freemarker.ext.util.ModelCache; 75 import freemarker.ext.util.WrapperTemplateModel; 76 import freemarker.template.AdapterTemplateModel; 77 import freemarker.template.ObjectWrapper; 78 import freemarker.template.TemplateBooleanModel; 79 import freemarker.template.TemplateHashModel; 80 import freemarker.template.TemplateHashModelEx; 81 import freemarker.template.TemplateMethodModel; 82 import freemarker.template.TemplateMethodModelEx; 83 import freemarker.template.TemplateModel; 84 import freemarker.template.TemplateModelAdapter; 85 import freemarker.template.TemplateModelException; 86 import freemarker.template.TemplateNumberModel; 87 import freemarker.template.TemplateScalarModel; 88 import freemarker.template.TemplateSequenceModel; 89 import freemarker.template.utility.OptimizerUtil; 90 91 97 public class JythonWrapper implements ObjectWrapper 98 { 99 private static final Class PYOBJECT_CLASS = PyObject.class; 100 public static final JythonWrapper INSTANCE = new JythonWrapper(); 101 102 private final ModelCache modelCache = new ModelCache(this); 103 104 private boolean attributesShadowItems = true; 105 106 public JythonWrapper() 107 { 108 } 109 110 115 public void setUseCache(boolean useCache) 116 { 117 modelCache.setUseCache(useCache); 118 } 119 120 130 public synchronized void setAttributesShadowItems(boolean attributesShadowItems) 131 { 132 this.attributesShadowItems = attributesShadowItems; 133 } 134 135 boolean isAttributesShadowItems() 136 { 137 return attributesShadowItems; 138 } 139 140 153 public TemplateModel wrap(Object obj) 154 { 155 if(obj == null) { 156 return null; 157 } 158 if (obj instanceof TemplateModel) { 159 return (TemplateModel)obj; 160 } 161 if(obj instanceof TemplateModelAdapter) { 162 return ((TemplateModelAdapter)obj).getTemplateModel(); 163 } 164 boolean asHash = false; 165 boolean asSequence = false; 166 if(obj instanceof PyJavaInstance) { 167 Object jobj = ((PyJavaInstance)obj).__tojava__(java.lang.Object .class); 168 if(jobj instanceof TemplateModel) { 170 return (TemplateModel)jobj; 171 } 172 if(jobj instanceof Map ) { 173 asHash = true; 174 } 175 else if(jobj instanceof Collection ) { 176 asSequence = true; 177 if(!(jobj instanceof List )) { 182 obj = new ArrayList ((Collection )jobj); 183 } 184 } 185 } 186 187 if(!(obj instanceof PyObject)) 189 { 190 obj = Py.java2py(obj); 191 } 192 if(asHash || obj instanceof PyDictionary || obj instanceof PyStringMap) 193 { 194 return modelCache.getInstance(obj, JythonHashModel.FACTORY); 195 } 196 if(asSequence || obj instanceof PySequence) 197 { 198 return modelCache.getInstance(obj, JythonSequenceModel.FACTORY); 199 } 200 if(obj instanceof PyInteger || obj instanceof PyLong || obj instanceof PyFloat) 201 { 202 return modelCache.getInstance(obj, JythonNumberModel.FACTORY); 203 } 204 if(obj instanceof PyNone) { 205 return null; 206 } 207 return modelCache.getInstance(obj, JythonModel.FACTORY); 208 } 209 210 232 public PyObject unwrap(TemplateModel model) throws TemplateModelException 233 { 234 if(model instanceof AdapterTemplateModel) { 235 return Py.java2py(((AdapterTemplateModel)model).getAdaptedObject( 236 PYOBJECT_CLASS)); 237 } 238 if(model instanceof WrapperTemplateModel) { 239 return Py.java2py(((WrapperTemplateModel)model).getWrappedObject()); 240 } 241 242 if(model instanceof TemplateScalarModel) 244 { 245 return new PyString(((TemplateScalarModel)model).getAsString()); 246 } 247 248 if(model instanceof TemplateNumberModel) 250 { 251 Number number = ((TemplateNumberModel)model).getAsNumber(); 252 if(number instanceof BigDecimal ) 253 { 254 number = OptimizerUtil.optimizeNumberRepresentation(number); 255 } 256 if(number instanceof BigInteger ) 257 { 258 return new PyLong((BigInteger )number); 262 } 263 else 264 { 265 return Py.java2py(number); 266 } 267 } 268 return new TemplateModelToJythonAdapter(model); 270 } 271 272 private class TemplateModelToJythonAdapter extends PyObject 273 implements TemplateModelAdapter 274 { 275 private final TemplateModel model; 276 277 TemplateModelToJythonAdapter(TemplateModel model) 278 { 279 this.model = model; 280 } 281 282 public TemplateModel getTemplateModel() 283 { 284 return model; 285 } 286 287 public PyObject __finditem__(PyObject key) 288 { 289 if(key instanceof PyInteger) 290 { 291 return __finditem__(((PyInteger)key).getValue()); 292 } 293 return __finditem__(key.toString()); 294 } 295 296 public PyObject __finditem__(String key) 297 { 298 if(model instanceof TemplateHashModel) 299 { 300 try 301 { 302 return unwrap(((TemplateHashModel)model).get(key)); 303 } 304 catch(TemplateModelException e) 305 { 306 throw Py.JavaError(e); 307 } 308 } 309 throw Py.TypeError("item lookup on non-hash model (" + getModelClass() + ")"); 310 } 311 312 public PyObject __finditem__(int index) 313 { 314 if(model instanceof TemplateSequenceModel) 315 { 316 try 317 { 318 return unwrap(((TemplateSequenceModel)model).get(index)); 319 } 320 catch(TemplateModelException e) 321 { 322 throw Py.JavaError(e); 323 } 324 } 325 throw Py.TypeError("item lookup on non-sequence model (" + getModelClass() + ")"); 326 } 327 328 public PyObject __call__(PyObject args[], String keywords[]) 329 { 330 if(model instanceof TemplateMethodModel) 331 { 332 boolean isEx = model instanceof TemplateMethodModelEx; 333 List list = new ArrayList (args.length); 334 try 335 { 336 for(int i = 0; i < args.length; ++i) 337 { 338 list.add( 339 isEx 340 ? (Object )wrap(args[i]) 341 : (Object )( 342 args[i] == null 343 ? null 344 : args[i].toString())); 345 } 346 return unwrap((TemplateModel) ((TemplateMethodModelEx)model).exec(list)); 347 } 348 catch(TemplateModelException e) 349 { 350 throw Py.JavaError(e); 351 } 352 } 353 throw Py.TypeError("call of non-method model (" + getModelClass() + ")"); 354 } 355 356 public int __len__() 357 { 358 try 359 { 360 if(model instanceof TemplateSequenceModel) 361 { 362 return ((TemplateSequenceModel)model).size(); 363 } 364 if(model instanceof TemplateHashModelEx) 365 { 366 return ((TemplateHashModelEx)model).size(); 367 } 368 } 369 catch(TemplateModelException e) 370 { 371 throw Py.JavaError(e); 372 } 373 374 return 0; 375 } 376 377 public boolean __nonzero__() 378 { 379 try 380 { 381 if(model instanceof TemplateBooleanModel) 382 { 383 return ((TemplateBooleanModel)model).getAsBoolean(); 384 } 385 if(model instanceof TemplateSequenceModel) 386 { 387 return ((TemplateSequenceModel)model).size() > 0; 388 } 389 if(model instanceof TemplateHashModel) 390 { 391 return !((TemplateHashModelEx)model).isEmpty(); 392 } 393 } 394 catch(TemplateModelException e) 395 { 396 throw Py.JavaError(e); 397 } 398 return false; 399 } 400 401 private String getModelClass() 402 { 403 return model == null ? "null" : model.getClass().getName(); 404 } 405 } 406 } 407 | Popular Tags |