View Javadoc

1   /*
2    * Copyright 2006-2016 The JGUIraffe Team.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License")
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sf.jguiraffe.gui.builder.window;
17  
18  import java.util.Collection;
19  import java.util.HashMap;
20  import java.util.Map;
21  import java.util.Set;
22  
23  import net.sf.jguiraffe.di.impl.SimpleBeanStoreImpl;
24  
25  import org.apache.commons.jelly.JellyContext;
26  
27  /**
28   * <p>
29   * A data class that stores important information needed during a window builder
30   * process.
31   * </p>
32   * <p>
33   * An instance of this class lives in the Jelly context during execution of a
34   * Jelly script that makes use of the window builder library. It contains
35   * parameters required by tag handler classes, e.g. the window manager to use.
36   * It will also store the results of the builder operation.
37   * </p>
38   * <p>
39   * In most cases a builder script will define only a single result window (if
40   * any). In this case the result window can be set using the
41   * {@link #setResultWindow(Window)} method and queried using
42   * {@link #getResultWindow()}. However, scripts are allowed to define multiple
43   * windows (an example use case would be a simple message box window which is
44   * displayed by an action of the main window). This can be achieved by giving
45   * the windows unique names; i.e. the {@code name} attribute of the window tag
46   * must be defined. Then, instead of {@link #setResultWindow(Window)}, the
47   * {@link #putWindow(String, Window)} method can be called to add the result
48   * window to this data object. {@link #putWindow(String, Window)} adds the
49   * window to an internal map so that it can be queried later by its name.
50   * </p>
51   * <p>
52   * Some objects managed by this class are available to the dependency injection
53   * framework (they can be obtained through the <code>BeanContext</code> of the
54   * active builder). These are the following:
55   * <ul>
56   * <li>The result window (provided that it already has been set) can be obtained
57   * using the key <em>{@value #KEY_CURRENT_WINDOW}</em>.</li>
58   * <li>Windows that have been assigned a name can be queried directly. The
59   * prefix <em>{@value #WINDOW_PREFIX}</em> has to be used, e.g. {@code
60   * window:msgBox} returns the window with the name <em>msgBox</em>.</li>
61   * <li>The parent window (if available) can be queried using the key
62   * <em>{@value #KEY_PARENT_WINDOW}</em>.</li>
63   * <li>If the current form bean is needed, it can be found in the context under
64   * the key <em>{@value #KEY_FORM_BEAN}</em>.</li>
65   * <li>Finally the active instance of this class can be obtained under the key
66   * <em>{@value #KEY_WINDOW_BUILDER_DATA}</em>.</li>
67   * </ul>
68   * </p>
69   *
70   * @author Oliver Heger
71   * @version $Id: WindowBuilderData.java 205 2012-01-29 18:29:57Z oheger $
72   */
73  public class WindowBuilderData implements SimpleBeanStoreImpl.BeanContributor
74  {
75      /**
76       * Constant for the key, under which the current result window can be
77       * obtained from the builder's bean context.
78       */
79      public static final String KEY_CURRENT_WINDOW = "CURRENT_WINDOW";
80  
81      /**
82       * Constant for the key, under which the parent window can be obtained from
83       * the builder's bean context.
84       */
85      public static final String KEY_PARENT_WINDOW = "PARENT_WINDOW";
86  
87      /**
88       * Constant for the key, under which the current form bean can be obtained
89       * from the builder's bean context.
90       */
91      public static final String KEY_FORM_BEAN = "FORM_BEAN";
92  
93      /**
94       * Constant for the key, under which the instance of this class can be
95       * obtained from the builder's bean context.
96       */
97      public static final String KEY_WINDOW_BUILDER_DATA = "WINDOW_BUILDER_DATA";
98  
99      /**
100      * Constant for the prefix for window beans. If a window is to be queried by
101      * its name, this prefix has to be used.
102      */
103     public static final String WINDOW_PREFIX = "window:";
104 
105     /**
106      * Constant for the key under which an instance will be stored in the Jelly
107      * context.
108      */
109     private static final String CTX_KEY = WindowBuilderData.class.getName();
110 
111     /** A map for the named windows. */
112     private final Map<String, Window> windows;
113 
114     /** Stores a reference to the current window manager. */
115     private WindowManager windowManager;
116 
117     /** Stores a reference to the parent window. */
118     private Window parentWindow;
119 
120     /** Stores the result window. */
121     private Window resultWindow;
122 
123     /** Stores the form bean instance. */
124     private Object formBean;
125 
126     /** Stores the current Jelly context. */
127     private JellyContext context;
128 
129     /**
130      * Creates a new instance of {@code WindowBuilderData}.
131      */
132     public WindowBuilderData()
133     {
134         windows = new HashMap<String, Window>();
135     }
136 
137     /**
138      * Returns the form bean.
139      *
140      * @return the form bean
141      */
142     public Object getFormBean()
143     {
144         return formBean;
145     }
146 
147     /**
148      * Sets the form bean. This information will be processed by form
149      * controllers that can use it to initialize forms and store user input.
150      *
151      * @param formBean the form bean
152      */
153     public void setFormBean(Object formBean)
154     {
155         this.formBean = formBean;
156     }
157 
158     /**
159      * Returns the parent window of the new window.
160      *
161      * @return the parent window
162      */
163     public Window getParentWindow()
164     {
165         return parentWindow;
166     }
167 
168     /**
169      * Sets the parent window. The newly created window will be a child of this
170      * window. For top level windows this property should be <b>null</b>.
171      *
172      * @param parentWindow the parent window
173      */
174     public void setParentWindow(Window parentWindow)
175     {
176         this.parentWindow = parentWindow;
177     }
178 
179     /**
180      * Returns the result window of the builder process.
181      *
182      * @return the result window
183      */
184     public Window getResultWindow()
185     {
186         return resultWindow;
187     }
188 
189     /**
190      * Sets the result window. Used by window creating tag handler classes to
191      * store their results.
192      *
193      * @param resultWindow the result window
194      */
195     public void setResultWindow(Window resultWindow)
196     {
197         this.resultWindow = resultWindow;
198     }
199 
200     /**
201      * Returns the result window with the given name. Windows can be assigned a
202      * name. Using this name they can be queried. This is especially useful for
203      * builder scripts that define multiple windows. Using this method a
204      * specific window can be queried.
205      *
206      * @param name the name of the desired window
207      * @return the window with this name or <b>null</b> if it cannot be resolved
208      */
209     public Window getWindow(String name)
210     {
211         return windows.get(WINDOW_PREFIX + name);
212     }
213 
214     /**
215      * Returns the current {@code JellyContext}. This information can be useful
216      * when access to objects local to the current build operation is needed.
217      * Note that this property is only initialized after this object was stored
218      * in the context. (This is the case while a build operation is executing.)
219      * If this method is called before a context is available, an
220      * {@code IllegalStateException} exception is thrown.
221      *
222      * @return the current {@code JellyContext}
223      * @throws IllegalStateException if the current context is not yet available
224      * @since 1.3
225      */
226     public JellyContext getContext()
227     {
228         if (context == null)
229         {
230             throw new IllegalStateException("Context not available! "
231                     + "This method can only be called after this instance "
232                     + "has been stored in the Jelly context using put().");
233         }
234         return context;
235     }
236 
237     /**
238      * Adds a result window to this data object. This method can be called for
239      * each window created during the builder operation. If a name is specified,
240      * the window is stored in a map where it can be accessed later using this
241      * name (using {@link #getWindow(String)}). This method also invokes
242      * {@link #setResultWindow(Window)}, so that the passed in window becomes
243      * the result window. This means that if a script defines multiple windows,
244      * the last one becomes the official result window.
245      *
246      * @param name the name of the window; can be <b>null</b>, then the window
247      *        cannot be queried using {@link #getWindow(String)}
248      * @param window the window to be added
249      */
250     public void putWindow(String name, Window window)
251     {
252         setResultWindow(window);
253 
254         if (name != null)
255         {
256             windows.put(WINDOW_PREFIX + name, window);
257         }
258     }
259 
260     /**
261      * Returns the window manager.
262      *
263      * @return the window manager
264      */
265     public WindowManager getWindowManager()
266     {
267         return windowManager;
268     }
269 
270     /**
271      * Sets the window manager. Here the platform specific window manager must
272      * be set, which will be used for creating windows.
273      *
274      * @param windowManager the window manager to use
275      */
276     public void setWindowManager(WindowManager windowManager)
277     {
278         this.windowManager = windowManager;
279     }
280 
281     /**
282      * Obtains the names of the supported beans. This implementation adds the
283      * names of some static beans. If there are named windows, their names are
284      * added as well.
285      *
286      * @param names a set in which to store the bean names
287      */
288     public void beanNames(Set<String> names)
289     {
290         addBeanName(names, KEY_CURRENT_WINDOW, getResultWindow());
291         addBeanName(names, KEY_FORM_BEAN, getFormBean());
292         addBeanName(names, KEY_PARENT_WINDOW, getParentWindow());
293 
294         for (String name : windows.keySet())
295         {
296             names.add(name);
297         }
298     }
299 
300     /**
301      * Returns the bean with the specified name. This implementation supports a
302      * few objects that are managed by this object. Named windows can also be
303      * queried.
304      *
305      * @param name the name of the desired bean
306      * @return the bean with this name or <b>null</b> if it cannot be found
307      */
308     public Object getBean(String name)
309     {
310         Object bean = null;
311 
312         if (KEY_CURRENT_WINDOW.equals(name))
313         {
314             bean = getResultWindow();
315         }
316         else if (KEY_FORM_BEAN.equals(name))
317         {
318             bean = getFormBean();
319         }
320         else if (KEY_PARENT_WINDOW.equals(name))
321         {
322             bean = getParentWindow();
323         }
324         else if (name.startsWith(WINDOW_PREFIX))
325         {
326             bean = windows.get(name);
327         }
328 
329         return bean;
330     }
331 
332     /**
333      * Initializes the specified bean store. This implementation adds the static
334      * object references to the store and registers this object as bean
335      * contributor.
336      *
337      * @param store the store to be initialized
338      */
339     public void initBeanStore(SimpleBeanStoreImpl store)
340     {
341         store.addBean(KEY_WINDOW_BUILDER_DATA, this);
342         store.addBeanContributor(this);
343     }
344 
345     /**
346      * Stores this instance in the specified Jelly context.
347      *
348      * @param ctx the context (must not be <b>null</b>)
349      * @throws IllegalArgumentException if the context is <b>null</b>
350      */
351     public void put(JellyContext ctx)
352     {
353         if (ctx == null)
354         {
355             throw new IllegalArgumentException("Context must not be null!");
356         }
357         ctx.setVariable(CTX_KEY, this);
358         context = ctx;
359     }
360 
361     /**
362      * Returns the instance of this class stored in the specified Jelly context.
363      * If no instance can be found, <b>null</b> will be returned.
364      *
365      * @param context the Jelly context
366      * @return the instance found in this context
367      */
368     public static WindowBuilderData get(JellyContext context)
369     {
370         return (context != null) ? (WindowBuilderData) context
371                 .findVariable(CTX_KEY) : null;
372     }
373 
374     /**
375      * Helper method for adding a bean name to a collection only if the bean is
376      * not <b>null</b>.
377      *
378      * @param col the collection
379      * @param name the name
380      * @param bean the bean
381      */
382     private static void addBeanName(Collection<String> col, String name,
383             Object bean)
384     {
385         if (bean != null)
386         {
387             col.add(name);
388         }
389     }
390 }