2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to you under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shale.dialog.basic.config;
19  
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.net.URL;
23  import java.util.Map;
24  
25  import org.apache.commons.digester.Digester;
26  import org.apache.commons.digester.Rule;
27  import org.apache.shale.dialog.basic.model.Dialog;
28  import org.xml.sax.InputSource;
29  import org.xml.sax.SAXException;
30  
31  /***
32   * <p>Configuration utility for parsing configuration resources for
33   * defining dialogs.  This class has no dependencies on web tier APIs,
34   * only on the parsing technology (Commons Digester) being used.</p>
35   *
36   * <p>To use this utility, instantiate a new instance and set the
37   * <code>dialogs</code>, <code>resource</code>, and <code>validating</code>
38   * properties.  Then, call the <code>parse()</code> method.  You can parse
39   * more than one resource by resetting the <code>resource</code>
40   * property and calling <code>parse()</code> again.</p>
41   *
42   * @since 1.0.4
43   */
44  
45  public final class ConfigurationParser {
46  
47  
48      // ------------------------------------------------------ Instance Variables
49  
50  
51      /***
52       * <p>Registration information for the DTD we will use to validate.</p>
53       */
54      private static final String[] REGISTRATIONS =
55      { "-//Apache Software Foundation//DTD Shale Dialog Configuration 1.0//EN",
56        "/org/apache/shale/dialog/dialog-config_1_0.dtd",
57        "-//Apache Software Foundation//DTD Shale Dialog Configuration 1.1//EN",
58        "/org/apache/shale/dialog/dialog-config_1_1.dtd" };
59  
60  
61      // -------------------------------------------------------------- Properties
62  
63  
64      /***
65       * <p><code>Map</code> of <code>Dialog</code> instances resulting
66       * from parsing, keyed by dialog name.</p>
67       */
68      private Map dialogs = null;
69  
70  
71      /***
72       * <p>Return the <code>Map</code> of <code>Dialog</code> instances
73       * into which parsed information will be stored, keyed by dialog
74       * name.</p>
75       *
76       * @return The map of available {@link Dialog}s, keyed by name
77       */
78      public Map getDialogs() {
79          return this.dialogs;
80      }
81  
82  
83      /***
84       * <p>Set the <code>Map</code> of <code>Dialog</code> instances
85       * into which parsed information will be stored, keyed by dialog
86       * name.</p>
87       *
88       * @param dialogs The new map
89       */
90      public void setDialogs(Map dialogs) {
91          this.dialogs = dialogs;
92      }
93  
94  
95      /***
96       * <p>The URL of the configuration resource to be parsed.</p>
97       */
98      private URL resource = null;
99  
100 
101     /***
102      * <p>Return the URL of the configuration resource to be parsed.</p>
103      *
104      * @return The URL of the dialogs configuration resource
105      */
106     public URL getResource() {
107         return this.resource;
108     }
109 
110 
111     /***
112      * <p>Set the URL of the configuration resource to be parsed.</p>
113      *
114      * @param resource The new resource URL
115      */
116     public void setResource(URL resource) {
117         this.resource = resource;
118     }
119 
120 
121     /***
122      * <p>Flag indicating whether we should do a validating parse or not.</p>
123      */
124     private boolean validating = true;
125 
126 
127     /***
128      * <p>Return a flag indicating whether we will be doing a validating parse
129      * or not.  Default value is <code>true</code>.</p>
130      *
131      * @return Whether the parse is a validating one
132      */
133     public boolean isValidating() {
134         return this.validating;
135     }
136 
137 
138     /***
139      * <p>Set a flag indicating whether we will be doing a validating parse
140      * or not.</p>
141      *
142      * @param validating New flag value
143      */
144     public void setValidating(boolean validating) {
145         this.validating = validating;
146     }
147 
148 
149     // ---------------------------------------------------------- Public Methods
150 
151 
152     /***
153      * <p>Parse the configuration resource identified by the <code>resource</code>
154      * property, storing resulting information in the <code>Map</code> specified
155      * by the <code>dialogs</code> property.</p>
156      *
157      * @exception IOException if an input/output error occurs
158      * @exception SAXException if an XML parsing error occurs
159      */
160     public void parse() throws IOException, SAXException {
161 
162         Digester digester = digester();
163         digester.clear();
164         digester.push(getDialogs());
165         InputSource source = new InputSource(getResource().toExternalForm());
166         InputStream stream = null;
167         try {
168             stream = getResource().openStream();
169             source.setByteStream(stream);
170             digester.parse(source);
171         } catch (IOException e) {
172             throw e;
173         } catch (SAXException e) {
174             throw e;
175         } finally {
176             if (stream != null) {
177                 try {
178                     stream.close();
179                 } catch (IOException e) {
180                     ; // Fall through
181                 }
182             }
183         }
184 
185     }
186 
187 
188     // --------------------------------------------------------- Private Methods
189 
190 
191     /***
192      * <p>Return a fully configured <code>Digester</code> instance.</p>
193      *
194      * @return The fully configured {@link Digester} instance for parsing
195      *         the dialog configuration resource
196      */
197     private Digester digester() {
198 
199         Digester digester = new Digester();
200 
201         // Configure global characteristics
202         digester.setNamespaceAware(false);
203         digester.setUseContextClassLoader(true);
204         digester.setValidating(isValidating());
205 
206         // Register local copy of our DTDs
207         for (int i = 0; i < REGISTRATIONS.length; i += 2) {
208             URL url = this.getClass().getResource(REGISTRATIONS[i + 1]);
209             digester.register(REGISTRATIONS[i], url.toString());
210         }
211 
212         // Configure processing rules
213 
214         // dialogs/dialog
215         digester.addObjectCreate("dialogs/dialog", "className", DialogImpl.class);
216         digester.addSetProperties("dialogs/dialog");
217         digester.addSetProperty("dialogs/dialog/property", "name", "value");
218         digester.addRule("dialogs/dialog", new AddDialogRule());
219 
220         // dialogs/dialog/action
221         digester.addObjectCreate("dialogs/dialog/action", "className",
222                                  ActionStateImpl.class);
223         digester.addSetProperties("dialogs/dialog/action");
224         digester.addSetProperty("dialogs/dialog/action/property", "name", "value");
225         digester.addSetNext("dialogs/dialog/action",
226                             "addState", "org.apache.shale.dialog.basic.model.State");
227 
228         // dialogs/dialog/action/transition
229         digester.addObjectCreate("dialogs/dialog/action/transition", "className",
230                                  TransitionImpl.class);
231         digester.addSetProperties("dialogs/dialog/action/transition");
232         digester.addSetProperty("dialogs/dialog/action/transition/property", "name", "value");
233         digester.addSetNext("dialogs/dialog/action/transition",
234                             "addTransition", "org.apache.shale.dialog.basic.model.Transition");
235 
236         // dialogs/dialog/end
237         digester.addObjectCreate("dialogs/dialog/end", "className",
238                                  EndStateImpl.class);
239         digester.addSetProperties("dialogs/dialog/end");
240         digester.addSetProperty("dialogs/dialog/end/property", "name", "value");
241         digester.addSetNext("dialogs/dialog/end",
242                             "addState", "org.apache.shale.dialog.basic.model.State");
243 
244         // dialogs/dialog/end/transition
245         digester.addObjectCreate("dialogs/dialog/end/transition", "className",
246                                  TransitionImpl.class);
247         digester.addSetProperties("dialogs/dialog/end/transition");
248         digester.addSetProperty("dialogs/dialog/end/transition/property", "name", "value");
249         digester.addSetNext("dialogs/dialog/end/transition",
250                             "addTransition", "org.apache.shale.dialog.basic.model.Transition");
251 
252         // dialogs/dialog/subdialog
253         digester.addObjectCreate("dialogs/dialog/subdialog", "className",
254                                  SubdialogStateImpl.class);
255         digester.addSetProperties("dialogs/dialog/subdialog");
256         digester.addSetProperty("dialogs/dialog/subdialog/property", "name", "value");
257         digester.addSetNext("dialogs/dialog/subdialog",
258                             "addState", "org.apache.shale.dialog.basic.model.State");
259 
260         // dialogs/dialog/subdialog/transition
261         digester.addObjectCreate("dialogs/dialog/subdialog/transition", "className",
262                                  TransitionImpl.class);
263         digester.addSetProperties("dialogs/dialog/subdialog/transition");
264         digester.addSetProperty("dialogs/dialog/subdialog/transition/property", "name", "value");
265         digester.addSetNext("dialogs/dialog/subdialog/transition",
266                             "addTransition", "org.apache.shale.dialog.basic.model.Transition");
267 
268         // dialogs/dialog/transition
269         digester.addObjectCreate("dialogs/dialog/transition", "className",
270                                  TransitionImpl.class);
271         digester.addSetProperties("dialogs/dialog/transition");
272         digester.addSetProperty("dialogs/dialog/transition/property", "name", "value");
273         digester.addSetNext("dialogs/dialog/transition",
274                             "addTransition", "org.apache.shale.dialog.basic.model.Transition");
275 
276         // dialogs/dialog/view
277         digester.addObjectCreate("dialogs/dialog/view", "className",
278                                  ViewStateImpl.class);
279         digester.addSetProperties("dialogs/dialog/view");
280         digester.addSetProperty("dialogs/dialog/view/property", "name", "value");
281         digester.addSetNext("dialogs/dialog/view",
282                             "addState", "org.apache.shale.dialog.basic.model.State");
283 
284         // dialogs/dialog/view/transition
285         digester.addObjectCreate("dialogs/dialog/view/transition", "className",
286                                  TransitionImpl.class);
287         digester.addSetProperties("dialogs/dialog/view/transition");
288         digester.addSetProperty("dialogs/dialog/view/transition/property", "name", "value");
289         digester.addSetNext("dialogs/dialog/view/transition",
290                             "addTransition", "org.apache.shale.dialog.basic.model.Transition");
291 
292         return digester;
293 
294     }
295 
296 
297     // -------------------------------------------- Private Rule Implementations
298 
299 
300     /***
301      * <p>Custom <code>Digester</code> rule to add a dialog.</p>
302      */
303     static class AddDialogRule extends Rule {
304 
305         /***
306          * <p>Process the "end" event for this rule.</p>
307          *
308          * @param namespace XML namespace of this element
309          * @param name Name of this element
310          *
311          * @exception Exception if a processing exception occurs
312          */
313         public void end(String namespace, String name) throws Exception {
314 
315             Dialog dialog = (Dialog) getDigester().peek();
316             Map map = (Map) getDigester().peek(1);
317             map.put(dialog.getName(), dialog);
318 
319         }
320 
321     }
322 
323 
324 }