001    /* sillyview : a free model-view-controller system for Java
002     * Copyright (C) 2004 T.J. Willis
003     * 
004     * This program is free software; you can redistribute it and/or
005     * modify it under the terms of the GNU General Public License
006     * as published by the Free Software Foundation; either version 2
007     * of the License, or (at your option) any later version.
008     *      
009     * This program is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012     * GNU General Public License for more details.
013     *          
014     * You should have received a copy of the GNU General Public License
015     * along with this program; if not, write to the Free Software
016     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
017     *  
018     * $Header: /cvsroot/sillyview/sillyview/src/net/sourceforge/sillyview/VelocityModel.java,v 1.2 2004/05/15 01:58:51 tj_willis Exp $
019     */
020    package net.sourceforge.sillyview;
021    
022    import java.io.*;
023    import java.net.*;
024    import java.util.Hashtable;
025    import java.util.regex.*;
026    import javax.swing.*;
027    import javax.swing.border.*;
028    
029    import org.apache.velocity.Template;
030    import org.apache.velocity.VelocityContext;
031    import org.apache.velocity.app.Velocity;
032    import org.apache.velocity.exception.ParseErrorException;
033    import org.apache.velocity.exception.ResourceNotFoundException;
034    import org.apache.velocity.exception.ParseErrorException;
035    import org.apache.velocity.exception.MethodInvocationException;
036    
037    import org.apache.log4j.*;
038    
039    /**
040     * Creates a WidgetModel backed by a Velocity Template.
041     *
042     * @author <a href="mailto:tj_willis@users.sourceforge.net">T.J. Willis</a>
043     * @version 1.0
044     */
045    public class VelocityModel implements WidgetModel {
046        private static Category cat 
047            = Category.getInstance(VelocityModel.class.getName());
048    
049        /**
050         * The VelocityContext to which tokens are delegated.
051         *
052         */
053        protected VelocityContext context;
054        /**
055         * The raw velocity template.
056         *
057         */
058        protected String template;
059    
060        /**
061         * Initializes velocity and creates a new context.
062         */
063        private void init () 
064            throws java.lang.Exception
065        {
066            Velocity.init ();
067            context = new VelocityContext ();
068            template = null;
069        }
070    
071        /**
072         * Initializes Velocity, creates a new context, and sets this model's
073         * template to the file at the given URL.
074         *
075         * @param templateURL an <code>URL</code> value
076         * @exception IOException if an error occurs
077         * @exception Exception if an error occurs
078         */
079        public VelocityModel (URL templateURL) throws IOException, Exception {
080            init ();
081            template = getTemplate(templateURL);
082        }
083    
084        private String getTemplate(URL templateURL) throws IOException, Exception {
085            StringBuffer cont = new StringBuffer ();
086    
087            InputStream is = templateURL.openStream ();
088            InputStreamReader isr = new InputStreamReader (is);
089            BufferedReader in = new BufferedReader (isr);
090            String foo = in.readLine ();
091            while (foo != null) {
092                cont.append (foo).append ("\n");    // += foo +"\n";
093                foo = in.readLine ();
094            }
095            //is.flush();
096            is.close();
097            return cont.toString ();
098        }
099    
100    
101        /**
102         * Allows several models to share a context.  Assumes that
103         *  Velocity.init() has already been called.
104         * @param context a <code>VelocityContext</code> value
105         * @param templateURL an <code>URL</code> value
106         * @exception IOException if an error occurs
107         * @exception Exception if an error occurs
108         */
109        public VelocityModel(VelocityContext context, URL templateURL)
110           throws IOException, Exception
111        {
112            this.context = context;
113            template = getTemplate(templateURL);
114        }
115    
116        /**
117         * Creates a new <code>VelocityModel</code> instance with the
118         * given String as its template.
119         *
120         * @param templateString a <code>String</code> value
121         * @exception Exception if an error occurs
122         */
123        public VelocityModel (final String templateString) 
124            throws Exception 
125        {
126            init ();
127            template = templateString;
128        }
129    
130        /**
131         * Returns the current model as a String.
132         *
133         * @return an <code>Object</code> value
134         */
135        public Object getCurrentModel () {
136            return this.toString ();
137        }
138    
139        /**
140         * Returns the template without applying existing token values.
141         *
142         * @return an <code>Object</code> value
143         */
144        public Object getRawModel () {
145            return template;
146        }
147    
148        /**
149         * Updates the template without modifying the current tokens.
150         * @param newTemplate an <code>Object</code> value
151         */
152        public void setRawModel (final Object newTemplate) {
153            template = newTemplate.toString ();
154        }
155    
156        /**
157         * Uses Velocity.evaluate() to merge the current token values
158         * with the template string.
159         *
160         * @return a <code>String</code> value
161         */
162        public String toString () {
163            StringWriter w = new StringWriter();
164            try
165            {
166                Velocity.evaluate( context, w, "mystring", template );
167                w.flush();
168                w.close();
169            }
170            catch( ParseErrorException pee )
171            {
172                /*
173                 * thrown if something is wrong with the
174                 * syntax of our template string
175                 */
176                cat.error("ParseErrorException : ",pee);
177            }
178            catch( MethodInvocationException mee )
179            {
180                /*
181                 *  thrown if a method of a reference
182                 *  called by the template
183                 *  throws an exception. That won't happen here
184                 *  as we aren't calling any methods in this
185                 *  example, but we have to catch them anyway
186                 */
187                cat.error("MethodInvocationException : ",mee );
188            }
189            catch( Exception e )
190            {
191                cat.error("Exception : ",e );
192            }
193            //String s = TemplateParser.parseTemplate (template, props)
194                       ;
195            //  if(checkIfDefs)
196            //      return IfDefProcessor.processTokens(s,props);
197            return w.toString();
198        }
199    
200        /**
201         * Sets the named token, delegating it to the VelocityContext.
202         *
203         * @param key an <code>Object</code> value
204         * @param value an <code>Object</code> value
205         */
206        public void setToken (final Object key, final Object value) {
207            context.put(key.toString(),value);
208        }
209    
210        /**
211         * Returns the value of the named token, taking it from the
212         * VelocityContext.
213         *
214         * @param key an <code>Object</code> value
215         * @return an <code>Object</code> value
216         */
217        public Object getValue (final Object key) {
218            return context.get (key.toString());
219    
220        }
221    
222        /**
223         * Static factory method for creating a VelocityModel with the
224         * raw velocity template at the given URL.  Calls Velocity.init()
225         * and creates a new VelocityContext.
226         *
227         * @param url a <code>String</code> value
228         * @return a <code>VelocityModel</code> value
229         */
230        public static VelocityModel getModel (final String url) {
231            VelocityModel model = null;
232            try {
233                URL u = new java.net.URL (url);
234                model = new VelocityModel (u);
235            } catch (Exception e) {
236                cat.error("getting model: " + url,e);
237            } 
238            return model;
239        }
240    
241    }