Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

Application.java 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  1. /* *************************************************************************
  2. Enably Toolkit
  3. Development of Browser User Intarfaces Made Easy
  4. Copyright (C) 2000-2006 IT Mill Ltd
  5. *************************************************************************
  6. This product is distributed under commercial license that can be found
  7. from the product package on license/license.txt. Use of this product might
  8. require purchasing a commercial license from IT Mill Ltd. For guidelines
  9. on usage, see license/licensing-guidelines.html
  10. *************************************************************************
  11. For more information, contact:
  12. IT Mill Ltd phone: +358 2 4802 7180
  13. Ruukinkatu 2-4 fax: +358 2 4802 7181
  14. 20540, Turku email: info@enably.com
  15. Finland company www: www.enably.com
  16. Primary source for information and releases: www.enably.com
  17. ********************************************************************** */
  18. package com.enably.tk;
  19. import com.enably.tk.service.ApplicationContext;
  20. import com.enably.tk.terminal.*;
  21. import com.enably.tk.ui.AbstractComponent;
  22. import com.enably.tk.ui.Window;
  23. import java.util.Collection;
  24. import java.util.Collections;
  25. import java.util.Enumeration;
  26. import java.util.EventListener;
  27. import java.util.EventObject;
  28. import java.util.Hashtable;
  29. import java.util.Iterator;
  30. import java.util.LinkedList;
  31. import java.util.Locale;
  32. import java.util.Properties;
  33. import java.util.Random;
  34. import java.net.MalformedURLException;
  35. import java.net.URL;
  36. /** <p>Abstract base class required for all MillStone applications. This
  37. * class provides all the basic services required by the MillStone
  38. * framework. These services allow external discovery and manipulation of
  39. * the user, {@link com.enably.tk.ui.Window windows} and
  40. * themes, and starting and stopping the application.</p>
  41. *
  42. * <p>As mentioned, all MillStone applications must inherit this class.
  43. * However, this is almost all of what one needs to do to create a fully
  44. * functional MillStone application. The only thing a class inheriting the
  45. * <code>Application</code> needs to do is implement the <code>init()</code>
  46. * where it creates the windows it needs to perform its function. Note that
  47. * all MillStone applications must have at least one window: the main
  48. * window. The first unnamed window constructed by an application
  49. * automatically becomes the main window which behaves just like other
  50. * windows with one exception: when accessing windows using URLs the main
  51. * window corresponds to the application URL whereas other windows
  52. * correspond to a URL gotten by catenating the window's name to the
  53. * application URL.</p>
  54. *
  55. * <p>See the class <code>com.enably.tk.demo.HelloWorld</code> for
  56. * a simple example of a fully working MillStone Application.</p>
  57. *
  58. * <p><strong>Window access.</strong> <code>Application</code> provides
  59. * methods to list, add and remove the windows it contains.</p>
  60. *
  61. * <p><strong>Execution control.</strong> This class includes method to
  62. * start and finish the execution of the application. Being finished means
  63. * basically that no windows will be available from the application
  64. * anymore.</p>
  65. *
  66. * <p><strong>Theme selection.</strong> The MillStone theme selection
  67. * process allows a theme to be specified at three different levels. When
  68. * a window's theme needs to be found out, the window itself is queried
  69. * for a preferred theme. If the window does not prefer a specific theme,
  70. * the application containing the window is queried. If neither the
  71. * application prefers a theme, the default theme for the
  72. * {@link com.enably.tk.terminal.Terminal terminal} is used. The
  73. * terminal always defines a default theme.</p>
  74. *
  75. * @author IT Mill Ltd.
  76. * @version @VERSION@
  77. * @since 3.0
  78. */
  79. public abstract class Application
  80. implements URIHandler, Terminal.ErrorListener {
  81. /** Random window name generator */
  82. private static Random nameGenerator = new Random();
  83. /** Application context the application is running in */
  84. private ApplicationContext context;
  85. /** The current user or <code>null</code> if no user has logged in. */
  86. private Object user;
  87. /** Mapping from window name to window instance */
  88. private Hashtable windows = new Hashtable();
  89. /** Main window of the application. */
  90. private Window mainWindow = null;
  91. /** The application's URL. */
  92. private URL applicationUrl;
  93. /** Name of the theme currently used by the application. */
  94. private String theme = null;
  95. /** Application status */
  96. private boolean applicationIsRunning = false;
  97. /** Application properties */
  98. private Properties properties;
  99. /** Default locale of the application. */
  100. private Locale locale;
  101. /** List of listeners listening user changes */
  102. private LinkedList userChangeListeners = null;
  103. /** Window attach listeners */
  104. private LinkedList windowAttachListeners = null;
  105. /** Window detach listeners */
  106. private LinkedList windowDetachListeners = null;
  107. /** Application error listeners */
  108. private LinkedList errorListeners = null;
  109. /** Application resource mapping: key <-> resource */
  110. private Hashtable resourceKeyMap = new Hashtable();
  111. private Hashtable keyResourceMap = new Hashtable();
  112. private long lastResourceKeyNumber = 0;
  113. /** URL the user is redirected to on application close or
  114. * null if application is just closed */
  115. private String logoutURL = null;
  116. /** Gets a window by name. Returns <code>null</code>
  117. * if the application is not running or it does not contain a window
  118. * corresponding to <code>name</code>.
  119. *
  120. * @param name The name of the window.
  121. * @return The window associated with the given URI or <code>null</code>
  122. */
  123. public Window getWindow(String name) {
  124. // For closed app, do not give any windows
  125. if (!isRunning())
  126. return null;
  127. // Get the window by name
  128. Window window = (Window) windows.get(name);
  129. return window;
  130. }
  131. /** Adds a new window to the application.
  132. *
  133. * <p>This implicitly invokes the
  134. * {@link com.enably.tk.ui.Window#setApplication(Application)}
  135. * method. </p>
  136. *
  137. * @param window the new <code>Window</code> to add
  138. * @throws IllegalArgumentException if a window with the same name
  139. * as the new window already exists in the application
  140. * @throws NullPointerException if the given <code>Window</code> or
  141. * its name is <code>null</code>
  142. */
  143. public void addWindow(Window window)
  144. throws IllegalArgumentException, NullPointerException {
  145. // Nulls can not be added to application
  146. if (window == null)
  147. return;
  148. // Get the naming proposal from window
  149. String name = window.getName();
  150. // Check that the application does not already contain
  151. // window having the same name
  152. if (name != null && windows.containsKey(name)) {
  153. // If the window is already added
  154. if (window == windows.get(name))
  155. return;
  156. // Otherwise complain
  157. throw new IllegalArgumentException(
  158. "Window with name '"
  159. + window.getName()
  160. + "' is already present in the application");
  161. }
  162. // If the name of the window is null, the window is automatically named
  163. if (name == null) {
  164. boolean accepted = false;
  165. while (!accepted) {
  166. // Try another name
  167. name = String.valueOf(Math.abs(nameGenerator.nextInt()));
  168. if (!windows.containsKey(name))
  169. accepted = true;
  170. }
  171. window.setName(name);
  172. }
  173. // Add the window to application
  174. windows.put(name, window);
  175. window.setApplication(this);
  176. // Fire window attach event
  177. if (windowAttachListeners != null) {
  178. Object[] listeners = windowAttachListeners.toArray();
  179. WindowAttachEvent event = new WindowAttachEvent(window);
  180. for (int i = 0; i < listeners.length; i++) {
  181. ((WindowAttachListener) listeners[i]).windowAttached(event);
  182. }
  183. }
  184. // If no main window is set, declare the window to be main window
  185. if (getMainWindow() == null)
  186. setMainWindow(window);
  187. }
  188. /** Removes the specified window from the application.
  189. *
  190. * @param window The window to be removed
  191. */
  192. public void removeWindow(Window window) {
  193. if (window != null && windows.contains(window)) {
  194. // Remove window from application
  195. windows.remove(window.getName());
  196. // If the window was main window, clear it
  197. if (getMainWindow() == window)
  198. setMainWindow(null);
  199. // Remove application from window
  200. if (window.getApplication() == this)
  201. window.setApplication(null);
  202. // Fire window detach event
  203. if (windowDetachListeners != null) {
  204. Object[] listeners = windowDetachListeners.toArray();
  205. WindowDetachEvent event = new WindowDetachEvent(window);
  206. for (int i = 0; i < listeners.length; i++) {
  207. ((WindowDetachListener) listeners[i]).windowDetached(event);
  208. }
  209. }
  210. }
  211. }
  212. /** Gets the user of the application.
  213. *
  214. * @return User of the application.
  215. */
  216. public Object getUser() {
  217. return user;
  218. }
  219. /** Sets the user of the application instance. An application instance
  220. * may have a user associated to it. This can be set in login procedure
  221. * or application initialization. A component performing the user login
  222. * procedure can assign the user property of the application and make
  223. * the user object available to other components of the application.
  224. *
  225. * @param user the new user.
  226. */
  227. public void setUser(Object user) {
  228. Object prevUser = this.user;
  229. if (user != prevUser && (user == null || !user.equals(prevUser))) {
  230. this.user = user;
  231. if (userChangeListeners != null) {
  232. Object[] listeners = userChangeListeners.toArray();
  233. UserChangeEvent event =
  234. new UserChangeEvent(this, user, prevUser);
  235. for (int i = 0; i < listeners.length; i++) {
  236. ((UserChangeListener) listeners[i]).applicationUserChanged(
  237. event);
  238. }
  239. }
  240. }
  241. }
  242. /** Gets the URL of the application.
  243. *
  244. * @return the application's URL.
  245. */
  246. public URL getURL() {
  247. return applicationUrl;
  248. }
  249. /** Ends the Application. In effect this will cause the application stop
  250. * returning any windows when asked.
  251. */
  252. public void close() {
  253. applicationIsRunning = false;
  254. }
  255. /** Starts the application on the given URL. After this call the
  256. * application corresponds to the given URL and it will return windows
  257. * when asked for them.
  258. *
  259. * @param applicationUrl The URL the application should respond to
  260. * @param applicationProperties Application properties as specified by the adapter.
  261. * @param context The context application will be running in
  262. *
  263. */
  264. public void start(URL applicationUrl, Properties applicationProperties, ApplicationContext context) {
  265. this.applicationUrl = applicationUrl;
  266. this.properties = applicationProperties;
  267. this.context = context;
  268. init();
  269. applicationIsRunning = true;
  270. }
  271. /** Tests if the application is running or if it has it been finished.
  272. *
  273. * @return <code>true</code> if the application is running,
  274. * <code>false</code> if not
  275. */
  276. public boolean isRunning() {
  277. return applicationIsRunning;
  278. }
  279. /** Gets the set of windows contained by the application.
  280. *
  281. * @return Unmodifiable collection of windows
  282. */
  283. public Collection getWindows() {
  284. return Collections.unmodifiableCollection(windows.values());
  285. }
  286. /** Main initializer of the application. This method is called by the
  287. * framework when the application is started, and it should perform
  288. * whatever initialization operations the application needs, such
  289. * as creating windows and adding components to them.
  290. */
  291. public abstract void init();
  292. /** Gets the application's theme. The application's theme is the default
  293. * theme used by all the windows in it that do not explicitly specify a
  294. * theme. If the application theme is not explicitly set, the
  295. * <code>null</code> is returned.
  296. *
  297. * @return the name of the application's theme
  298. */
  299. public String getTheme() {
  300. return theme;
  301. }
  302. /** Sets the application's theme. Note that this theme can be overridden
  303. * by the windows. <code>null</code> implies the default terminal theme.
  304. *
  305. * @param theme The new theme for this application
  306. */
  307. public void setTheme(String theme) {
  308. // Collect list of windows not having the current or future theme
  309. LinkedList toBeUpdated = new LinkedList();
  310. String myTheme = this.getTheme();
  311. for (Iterator i = getWindows().iterator(); i.hasNext();) {
  312. Window w = (Window) i.next();
  313. String windowTheme = w.getTheme();
  314. if ((windowTheme == null)
  315. || (!theme.equals(windowTheme) && windowTheme.equals(myTheme))) {
  316. toBeUpdated.add(w);
  317. }
  318. }
  319. // Update theme
  320. this.theme = theme;
  321. // Ask windows to update themselves
  322. for (Iterator i = getWindows().iterator(); i.hasNext();)
  323. ((Window) i.next()).requestRepaint();
  324. }
  325. /** Returns the mainWindow of the application.
  326. * @return Window
  327. */
  328. public Window getMainWindow() {
  329. return mainWindow;
  330. }
  331. /** Sets the mainWindow. If the main window is not explicitly set, the
  332. * main window defaults to first created window. Setting window as
  333. * a main window of this application also adds the window to this application.
  334. * @param mainWindow The mainWindow to set
  335. */
  336. public void setMainWindow(Window mainWindow) {
  337. addWindow(mainWindow);
  338. this.mainWindow = mainWindow;
  339. }
  340. /** Returns an enumeration of all the names in this application.
  341. * @return an enumeration of all the keys in this property list, including the keys in
  342. * the default property list.
  343. *
  344. */
  345. public Enumeration getPropertyNames() {
  346. return this.properties.propertyNames();
  347. }
  348. /** Searches for the property with the specified name in this application.
  349. * The method returns null if the property is not found.
  350. *
  351. * @param name The name of the property.
  352. * @return The value in this property list with the specified key value.
  353. */
  354. public String getProperty(String name) {
  355. return this.properties.getProperty(name);
  356. }
  357. /** Add new resource to the application. The resource can be
  358. * accessed by the user of the application. */
  359. public void addResource(ApplicationResource resource) {
  360. // Check if the resource is already mapped
  361. if (resourceKeyMap.containsKey(resource))
  362. return;
  363. // Generate key
  364. String key = String.valueOf(++lastResourceKeyNumber);
  365. // Add the resource to mappings
  366. resourceKeyMap.put(resource, key);
  367. keyResourceMap.put(key, resource);
  368. }
  369. /** Remove resource from the application. */
  370. public void removeResource(ApplicationResource resource) {
  371. Object key = resourceKeyMap.get(resource);
  372. if (key != null) {
  373. resourceKeyMap.remove(resource);
  374. keyResourceMap.remove(key);
  375. }
  376. }
  377. /** Get relative uri of the resource */
  378. public String getRelativeLocation(ApplicationResource resource) {
  379. // Get the key
  380. String key = (String) resourceKeyMap.get(resource);
  381. // If the resource is not registered, return null
  382. if (key == null)
  383. return null;
  384. String filename = resource.getFilename();
  385. if (filename == null)
  386. return "APP/" + key + "/";
  387. else
  388. return "APP/" + key + "/" + filename;
  389. }
  390. /* @see com.enably.tk.terminal.URIHandler#handleURI(URL, String)
  391. */
  392. public DownloadStream handleURI(
  393. URL context,
  394. String relativeUri) { // If the relative uri is null, we are ready
  395. if (relativeUri == null)
  396. return null;
  397. // Resolve prefix
  398. String prefix = relativeUri;
  399. int index = relativeUri.indexOf('/');
  400. if (index >= 0)
  401. prefix = relativeUri.substring(0, index);
  402. // Handle resource requests
  403. if (prefix.equals("APP")) {
  404. // Handle resource request
  405. int next = relativeUri.indexOf('/', index + 1);
  406. if (next < 0)
  407. return null;
  408. String key = relativeUri.substring(index + 1, next);
  409. ApplicationResource resource =
  410. (ApplicationResource) keyResourceMap.get(key);
  411. if (resource != null)
  412. return resource.getStream();
  413. // Resource requests override uri handling
  414. return null;
  415. }
  416. // If the uri is in some window, handle the window uri
  417. Window window = getWindow(prefix);
  418. if (window != null) {
  419. URL windowContext;
  420. try {
  421. windowContext = new URL(context, prefix + "/");
  422. String windowUri =
  423. relativeUri.length() > prefix.length() + 1
  424. ? relativeUri.substring(prefix.length() + 1)
  425. : "";
  426. return window.handleURI(windowContext, windowUri);
  427. } catch (MalformedURLException e) {
  428. return null;
  429. }
  430. }
  431. // If the uri was not pointing to a window, handle the
  432. // uri in main window
  433. window = getMainWindow();
  434. if (window != null)
  435. return window.handleURI(context, relativeUri);
  436. return null;
  437. }
  438. /** Get thed default locale for this application */
  439. public Locale getLocale() {
  440. if (this.locale != null)
  441. return this.locale;
  442. return Locale.getDefault();
  443. }
  444. /** Set the default locale for this application */
  445. public void setLocale(Locale locale) {
  446. this.locale = locale;
  447. }
  448. /** Application user change event sent when the setUser is called to
  449. * change the current user of the application.
  450. * @version @VERSION@
  451. * @since 3.0
  452. */
  453. public class UserChangeEvent extends java.util.EventObject {
  454. /**
  455. * Serial generated by eclipse.
  456. */
  457. private static final long serialVersionUID = 3544951069307188281L;
  458. /** New user of the application */
  459. private Object newUser;
  460. /** Previous user of the application */
  461. private Object prevUser;
  462. /** Contructor for user change event */
  463. public UserChangeEvent(
  464. Application source,
  465. Object newUser,
  466. Object prevUser) {
  467. super(source);
  468. this.newUser = newUser;
  469. this.prevUser = prevUser;
  470. }
  471. /** Get the new user of the application */
  472. public Object getNewUser() {
  473. return newUser;
  474. }
  475. /** Get the previous user of the application */
  476. public Object getPreviousUser() {
  477. return prevUser;
  478. }
  479. /** Get the application where the user change occurred */
  480. public Application getApplication() {
  481. return (Application) getSource();
  482. }
  483. }
  484. /** Public interface for listening application user changes
  485. * @version @VERSION@
  486. * @since 3.0
  487. */
  488. public interface UserChangeListener extends EventListener {
  489. /** Invoked when the application user has changed */
  490. public void applicationUserChanged(Application.UserChangeEvent event);
  491. }
  492. /** Add user change listener */
  493. public void addListener(UserChangeListener listener) {
  494. if (userChangeListeners == null)
  495. userChangeListeners = new LinkedList();
  496. userChangeListeners.add(listener);
  497. }
  498. /** Remove user change listener */
  499. public void removeListener(UserChangeListener listener) {
  500. if (userChangeListeners == null)
  501. return;
  502. userChangeListeners.remove(listener);
  503. if (userChangeListeners.isEmpty())
  504. userChangeListeners = null;
  505. }
  506. /** Window detach event */
  507. public class WindowDetachEvent extends EventObject {
  508. /**
  509. * Serial generated by eclipse.
  510. */
  511. private static final long serialVersionUID = 3544669568644691769L;
  512. private Window window;
  513. /** Create event.
  514. * @param window Detached window.
  515. */
  516. public WindowDetachEvent(Window window) {
  517. super(Application.this);
  518. this.window = window;
  519. }
  520. /** Get the detached window */
  521. public Window getWindow() {
  522. return window;
  523. }
  524. /** Get the application from which the window was detached */
  525. public Application getApplication() {
  526. return (Application) getSource();
  527. }
  528. }
  529. /** Window attach event */
  530. public class WindowAttachEvent extends EventObject {
  531. /**
  532. * Serial generated by eclipse.
  533. */
  534. private static final long serialVersionUID = 3977578104367822392L;
  535. private Window window;
  536. /** Create event.
  537. * @param window Attached window.
  538. */
  539. public WindowAttachEvent(Window window) {
  540. super(Application.this);
  541. this.window = window;
  542. }
  543. /** Get the attached window */
  544. public Window getWindow() {
  545. return window;
  546. }
  547. /** Get the application to which the window was attached */
  548. public Application getApplication() {
  549. return (Application) getSource();
  550. }
  551. }
  552. /** Window attach listener interface */
  553. public interface WindowAttachListener {
  554. /** Window attached */
  555. public void windowAttached(WindowAttachEvent event);
  556. }
  557. /** Window detach listener interface */
  558. public interface WindowDetachListener {
  559. /** Window attached */
  560. public void windowDetached(WindowDetachEvent event);
  561. }
  562. /** Add window attach listener */
  563. public void addListener(WindowAttachListener listener) {
  564. if (windowAttachListeners == null)
  565. windowAttachListeners = new LinkedList();
  566. windowAttachListeners.add(listener);
  567. }
  568. /** Add window detach listener */
  569. public void addListener(WindowDetachListener listener) {
  570. if (windowDetachListeners == null)
  571. windowDetachListeners = new LinkedList();
  572. windowDetachListeners.add(listener);
  573. }
  574. /** Remove window attach listener */
  575. public void removeListener(WindowAttachListener listener) {
  576. if (windowAttachListeners != null) {
  577. windowAttachListeners.remove(listener);
  578. if (windowAttachListeners.isEmpty())
  579. windowAttachListeners = null;
  580. }
  581. }
  582. /** Remove window detach listener */
  583. public void removeListener(WindowDetachListener listener) {
  584. if (windowDetachListeners != null) {
  585. windowDetachListeners.remove(listener);
  586. if (windowDetachListeners.isEmpty())
  587. windowDetachListeners = null;
  588. }
  589. }
  590. /** Returns the URL user is redirected to on application close.
  591. * If the URL is null, the application is closed normally as
  592. * defined by the application running environment: Desctop application
  593. * just closes the application window and web-application redirects
  594. * the browser to application main URL.
  595. *
  596. * @return URL
  597. */
  598. public String getLogoutURL() {
  599. return logoutURL;
  600. }
  601. /** Sets the URL user is redirected to on application close.
  602. * If the URL is null, the application is closed normally as
  603. * defined by the application running environment: Desctop application
  604. * just closes the application window and web-application redirects
  605. * the browser to application main URL.
  606. *
  607. * @param logoutURL The logoutURL to set
  608. */
  609. public void setLogoutURL(String logoutURL) {
  610. this.logoutURL = logoutURL;
  611. }
  612. /**
  613. * @see com.enably.tk.terminal.Terminal.ErrorListener#terminalError(com.enably.tk.terminal.Terminal.ErrorEvent)
  614. */
  615. public void terminalError(Terminal.ErrorEvent event) {
  616. // Find the original source of the error/exception
  617. Object owner = null;
  618. if (event instanceof VariableOwner.ErrorEvent) {
  619. owner = ((VariableOwner.ErrorEvent) event).getVariableOwner();
  620. } else if (event instanceof URIHandler.ErrorEvent) {
  621. owner = ((URIHandler.ErrorEvent) event).getURIHandler();
  622. } else if (event instanceof ParameterHandler.ErrorEvent) {
  623. owner = ((ParameterHandler.ErrorEvent) event).getParameterHandler();
  624. }
  625. // Show the error in AbstractComponent
  626. if (owner instanceof AbstractComponent) {
  627. Throwable e = event.getThrowable();
  628. if (e instanceof ErrorMessage)
  629. ((AbstractComponent) owner).setComponentError((ErrorMessage) e);
  630. else
  631. ((AbstractComponent) owner).setComponentError(
  632. new SystemError(e));
  633. }
  634. }
  635. /** Get application context.
  636. *
  637. * The application context is the environment where the application
  638. * is running in.
  639. */
  640. public ApplicationContext getContext() {
  641. return context;
  642. }
  643. }