001: /*
002: * Copyright (c) 2003 The Visigoth Software Society. All rights
003: * reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions
007: * are met:
008: *
009: * 1. Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: *
012: * 2. Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in
014: * the documentation and/or other materials provided with the
015: * distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowledgement:
019: * "This product includes software developed by the
020: * Visigoth Software Society (http://www.visigoths.org/)."
021: * Alternately, this acknowledgement may appear in the software itself,
022: * if and wherever such third-party acknowledgements normally appear.
023: *
024: * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
025: * project contributors may be used to endorse or promote products derived
026: * from this software without prior written permission. For written
027: * permission, please contact visigoths@visigoths.org.
028: *
029: * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
030: * nor may "FreeMarker" or "Visigoth" appear in their names
031: * without prior written permission of the Visigoth Software Society.
032: *
033: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
034: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
035: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
036: * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
037: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
038: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
039: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
040: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
041: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
042: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
043: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
044: * SUCH DAMAGE.
045: * ====================================================================
046: *
047: * This software consists of voluntary contributions made by many
048: * individuals on behalf of the Visigoth Software Society. For more
049: * information on the Visigoth Software Society, please see
050: * http://www.visigoths.org/
051: */
052:
053: package freemarker.ext.jython;
054:
055: import java.util.Iterator;
056: import java.util.List;
057:
058: import org.python.core.Py;
059: import org.python.core.PyException;
060: import org.python.core.PyObject;
061:
062: import freemarker.ext.util.ModelFactory;
063: import freemarker.ext.util.WrapperTemplateModel;
064: import freemarker.template.AdapterTemplateModel;
065: import freemarker.template.ObjectWrapper;
066: import freemarker.template.TemplateBooleanModel;
067: import freemarker.template.TemplateHashModel;
068: import freemarker.template.TemplateMethodModelEx;
069: import freemarker.template.TemplateModel;
070: import freemarker.template.TemplateModelException;
071: import freemarker.template.TemplateScalarModel;
072:
073: /**
074: * Generic model for arbitrary Jython objects.
075: * @version $Id: JythonModel.java,v 1.14 2005/06/12 19:03:06 szegedia Exp $
076: * @author Attila Szegedi
077: */
078: public class JythonModel implements TemplateBooleanModel,
079: TemplateScalarModel, TemplateHashModel, TemplateMethodModelEx,
080: AdapterTemplateModel, WrapperTemplateModel {
081: protected final PyObject object;
082: protected final JythonWrapper wrapper;
083:
084: static final ModelFactory FACTORY = new ModelFactory() {
085: public TemplateModel create(Object object, ObjectWrapper wrapper) {
086: return new JythonModel((PyObject) object,
087: (JythonWrapper) wrapper);
088: }
089: };
090:
091: public JythonModel(PyObject object, JythonWrapper wrapper) {
092: this .object = object;
093: this .wrapper = wrapper;
094: }
095:
096: /**
097: * Returns the value of {@link PyObject#__nonzero__()}.
098: */
099: public boolean getAsBoolean() throws TemplateModelException {
100: try {
101: return object.__nonzero__();
102: } catch (PyException e) {
103: throw new TemplateModelException(e);
104: }
105: }
106:
107: /**
108: * Returns the value of {@link Object#toString()}.
109: */
110: public String getAsString() throws TemplateModelException {
111: try {
112: return object.toString();
113: } catch (PyException e) {
114: throw new TemplateModelException(e);
115: }
116: }
117:
118: /**
119: * Calls {@link PyObject#__findattr__(java.lang.String)}, then if it
120: * returns null calls {@link PyObject#__finditem__(java.lang.String)}.
121: * If {@link JythonWrapper#setAttributesShadowItems(boolean)} was called
122: * with <code>false</code>, the order of calls is reversed (that is, item
123: * lookup takes precedence over attribute lookup).
124: */
125: public TemplateModel get(String key) throws TemplateModelException {
126: if (key != null) {
127: key = key.intern();
128: }
129:
130: PyObject obj = null;
131:
132: try {
133: if (wrapper.isAttributesShadowItems()) {
134: obj = object.__findattr__(key);
135: if (obj == null) {
136: obj = object.__finditem__(key);
137: }
138: } else {
139: obj = object.__finditem__(key);
140: if (obj == null) {
141: obj = object.__findattr__(key);
142: }
143: }
144: } catch (PyException e) {
145: throw new TemplateModelException(e);
146: }
147:
148: return wrapper.wrap(obj);
149: }
150:
151: /**
152: * Returns {@link PyObject#__len__()}<code> == 0</code>.
153: */
154: public boolean isEmpty() throws TemplateModelException {
155: try {
156: return object.__len__() == 0;
157: } catch (PyException e) {
158: throw new TemplateModelException(e);
159: }
160: }
161:
162: /**
163: * @see freemarker.template.TemplateMethodModel#exec(List)
164: */
165: public Object exec(List arguments) throws TemplateModelException {
166: int size = arguments.size();
167: try {
168: switch (size) {
169: case 0: {
170: return wrapper.wrap(object.__call__());
171: }
172: case 1: {
173: return wrapper.wrap(object.__call__(wrapper
174: .unwrap((TemplateModel) arguments.get(0))));
175: }
176: default: {
177: PyObject[] pyargs = new PyObject[size];
178: int i = 0;
179: for (Iterator arg = arguments.iterator(); arg.hasNext();) {
180: pyargs[i++] = wrapper.unwrap((TemplateModel) arg
181: .next());
182: }
183: return wrapper.wrap(object.__call__(pyargs));
184: }
185: }
186: } catch (PyException e) {
187: throw new TemplateModelException(e);
188: }
189: }
190:
191: public Object getAdaptedObject(Class hint) {
192: if (object == null) {
193: return null;
194: }
195: Object view = object.__tojava__(hint);
196: if (view == Py.NoConversion) {
197: view = object.__tojava__(Object.class);
198: }
199: return view;
200: }
201:
202: public Object getWrappedObject() {
203: return object == null ? null : object.__tojava__(Object.class);
204: }
205: }
|