View Javadoc
1   /*
2    * $Source$
3    * $Revision$
4    *
5    * Copyright (C) 2005 Tim Pizey
6    *
7    * Part of Melati (http://melati.org), a framework for the rapid
8    * development of clean, maintainable web applications.
9    *
10   * Melati is free software; Permission is granted to copy, distribute
11   * and/or modify this software under the terms either:
12   *
13   * a) the GNU General Public License as published by the Free Software
14   *    Foundation; either version 2 of the License, or (at your option)
15   *    any later version,
16   *
17   *    or
18   *
19   * b) any version of the Melati Software License, as published
20   *    at http://melati.org
21   *
22   * You should have received a copy of the GNU General Public License and
23   * the Melati Software License along with this program;
24   * if not, write to the Free Software Foundation, Inc.,
25   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26   * GNU General Public License and visit http://melati.org to obtain the
27   * Melati Software License.
28   *
29   * Feel free to contact the Developers of Melati (http://melati.org),
30   * if you would like to work out a different arrangement than the options
31   * outlined here.  It is our intention to allow Melati to be used by as
32   * wide an audience as possible.
33   *
34   * This program is distributed in the hope that it will be useful,
35   * but WITHOUT ANY WARRANTY; without even the implied warranty of
36   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37   * GNU General Public License for more details.
38   *
39   * Contact details for copyright holder:
40   *
41   *     Tim Pizey <timp At paneris.org>
42   *     http://paneris.org/~timp
43   */
44  
45  package org.melati.app;
46  
47  import java.io.File;
48  import java.io.FileNotFoundException;
49  import java.io.FileOutputStream;
50  import java.io.IOException;
51  import java.io.OutputStreamWriter;
52  import java.io.PrintStream;
53  import java.util.Properties;
54  
55  import org.melati.Melati;
56  import org.melati.MelatiConfig;
57  import org.melati.PoemContext;
58  import org.melati.poem.PoemDatabaseFactory;
59  import org.melati.poem.util.ArrayUtils;
60  import org.melati.util.MelatiException;
61  import org.melati.util.MelatiIOException;
62  import org.melati.util.MelatiSimpleWriter;
63  import org.melati.util.MelatiWriter;
64  
65  /**
66   * ConfigApp is the simplest way to use Melati.
67   * 
68   * All a ConfigApp does is to configure a Melati. Importantly it does not
69   * establish a Poem session leaving you to do this for yourself.
70   * 
71   * If you want a POEM session established, please extend {@link AbstractPoemApp}.
72   * 
73   * ConfigApp does set up a basic {@link PoemContext} with the Method set, but
74   * not the POEM logicaldatabase, table or troid.
75   * 
76   * The arguments are expected to end with a freeform string telling your
77   * application what it is meant to do. This is automatically made available in
78   * templates as <TT>$melati.Method</TT>.
79   * 
80   * You can change the way these things are determined by overriding
81   * {@link #poemContext}.
82   */
83  
84  public abstract class AbstractConfigApp implements App {
85  
86    protected static MelatiConfig melatiConfig;
87  
88    protected PrintStream output = System.out;
89  
90    /**
91     * Initialise.
92     * 
93     * @param args
94     *          the command line arguments
95     * @return a newly created Melati
96     * @throws MelatiException
97     *           if something goes wrong during initialisation
98     */
99    public Melati init(String[] args) throws MelatiException {
100       melatiConfig = melatiConfig();
101     String[] argumentsWithoutOutput = applyNamedArguments(args);
102     MelatiWriter out = new MelatiSimpleWriter(new OutputStreamWriter(output));
103     Melati melati = new Melati(melatiConfig, out);
104     melati.setArguments(argumentsWithoutOutput);
105     melati.setPoemContext(poemContext(melati));
106 
107     return melati;
108   }
109 
110   /**
111    * Clean up at end of run. Overridden in PoemApp.
112    * 
113    * @param melati
114    *          the melati
115    * @throws IOException if there is an io problem
116    */
117   public void term(Melati melati) throws IOException {
118     melati.write();
119   }
120 
121   /**
122    * Set application properties from the default properties file.
123    * 
124    * This method will look for a properties file called
125    * <tt>org.melati.MelatiConfig.properties</tt>; if it finds that the
126    * AccessHandler is an Http handler it will set the access handler to
127    * <code>OpenAccessHandler</code>.
128    * 
129    * Similarly ServletTemplateEngine is changed to TemplateEngine.
130    *  
131    * To override any setting from MelatiConfig.properties, simply override this
132    * method and return a vaild MelatiConfig.
133    * 
134    * eg to use a different AccessHandler from the default:
135    * 
136    * <PRE>
137    * protected MelatiConfig melatiConfig() throws MelatiException {
138    *   MelatiConfig config = super.melatiConfig();
139    *   config.setAccessHandler(new YourAccessHandler());
140    *   return config;
141    * }
142    * </PRE>
143    * 
144    * @throws MelatiException
145    *           if anything goes wrong with Melati
146    */
147   protected MelatiConfig melatiConfig() throws MelatiException {
148     Properties servletProperties = MelatiConfig.getProperties();
149 
150     if (servletProperties.getProperty("org.melati.MelatiConfig.templateEngine").equals(
151         "org.melati.template.webmacro.WebmacroServletTemplateEngine"))
152       servletProperties.setProperty("org.melati.MelatiConfig.templateEngine", 
153           "org.melati.template.webmacro.WebmacroTemplateEngine");
154     if (servletProperties.getProperty("org.melati.MelatiConfig.templateEngine").equals(
155         "org.melati.template.webmacro.VelocityServletTemplateEngine"))
156       servletProperties.setProperty("org.melati.MelatiConfig.templateEngine", 
157           "org.melati.template.webmacro.VelocityTemplateEngine");
158     if (servletProperties.getProperty("org.melati.MelatiConfig.templateEngine").equals(
159         "org.melati.template.webmacro.FreemarkerServletTemplateEngine"))
160       servletProperties.setProperty("org.melati.MelatiConfig.templateEngine", 
161           "org.melati.template.webmacro.FreemarkerTemplateEngine");
162        
163     if (servletProperties.getProperty("org.melati.MelatiConfig.accessHandler").equals(
164         "org.melati.login.HttpBasicAuthenticationAccessHandler"))
165       servletProperties.setProperty("org.melati.MelatiConfig.accessHandler", 
166           "org.melati.login.OpenAccessHandler");
167     if (servletProperties.getProperty("org.melati.MelatiConfig.accessHandler").equals(
168         "org.melati.login.HttpSessionAccessHandler"))
169       servletProperties.setProperty("org.melati.MelatiConfig.accessHandler", 
170           "org.melati.login.OpenAccessHandler");
171        
172     
173     MelatiConfig config = new MelatiConfig(servletProperties);
174 
175     return config;
176   }
177 
178   /**
179    * Do our thing.
180    */
181   public void run(String[] args) throws Exception {
182     Melati melati = init(args);
183     try { 
184       doConfiguredRequest(melati);
185     } finally {  
186       term(melati);
187       PoemDatabaseFactory.getPoemShutdownThread().run();
188     }
189   }
190 
191   /**
192    * This method <b>SHOULD</b> be overidden.
193    * 
194    * @return the System Administrators name.
195    */
196   public String getSysAdminName() {
197     return "nobody";
198   }
199 
200   /**
201    * This method <b>SHOULD</b> be overidden.
202    * 
203    * @return the System Administrators email address.
204    */
205   public String getSysAdminEmail() {
206     return "nobody@nobody.com";
207   }
208 
209   /**
210    * Set up the (@link PoemContext}, but only the Method.
211    * 
212    * @param melati
213    *          the current {@link Melati}
214    * @return a partially configured {@link PoemContext}
215    */
216   protected PoemContext poemContext(Melati melati) {
217     PoemContext it = new PoemContext();
218     String[] arguments = melati.getArguments();
219     if (arguments.length > 0)
220       it.setMethod(arguments[arguments.length - 1]);
221     return it;
222   }
223 
224   protected String[] applyNamedArguments(String[] arguments) {
225     String[] unnamedArguments = new String[] {};
226     boolean nextIsOutput = false;
227     for (int i = 0; i < arguments.length; i++) {
228       if (arguments[i].startsWith("-o"))
229         nextIsOutput = true;
230       else if (nextIsOutput) {
231         setOutput(arguments[i]);
232         nextIsOutput = false;
233       } else {
234         unnamedArguments = (String[])ArrayUtils.added(unnamedArguments,
235                 arguments[i]);
236       }
237     }
238 
239     return unnamedArguments;
240   }
241 
242   public void setOutput(String path) {
243     File outputFile;
244     try {
245       outputFile = new File(path).getCanonicalFile();
246     } catch (IOException e) {
247       throw new MelatiIOException(e);
248     }
249     File parent = new File(outputFile.getParent());
250     parent.mkdirs();
251     try {
252       outputFile.createNewFile();
253     } catch (IOException e) {
254       throw new MelatiIOException(
255           "Could not create " + outputFile.getAbsolutePath(), e);
256     }
257     try {
258       setOutput(new PrintStream(new FileOutputStream(outputFile)));
259     } catch (FileNotFoundException e) {
260       throw new MelatiIOException(e);
261     }
262   }
263 
264   /**
265    * {@inheritDoc}
266    * 
267    * @see org.melati.app.App#setOutput(java.io.PrintStream)
268    */
269   public void setOutput(PrintStream out) {
270     output = out;
271   }
272 
273   /**
274    * Instantiate this method to build up your own output.
275    * 
276    * @param melati
277    *          a configured {@link Melati}
278    * @throws Exception
279    *           if anything goes wrong
280    */
281   protected abstract void doConfiguredRequest(final Melati melati)
282           throws Exception;
283 
284 }