Coverage Report - org.openpermis.editor.policy.Application
 
Classes in this File Line Coverage Branch Coverage Complexity
Application
0%
0/93
0%
0/34
2.643
 
 1  
 /*
 2  
  * Copyright (c) 2009, Swiss Federal Department of Defence Civil Protection and Sport
 3  
  *                     (http://www.vbs.admin.ch)
 4  
  * Copyright (c) 2009, Ergon Informatik AG (http://www.ergon.ch)
 5  
  * All rights reserved.
 6  
  *
 7  
  * Licensed under the Open Permis License which accompanies this distribution,
 8  
  * and is available at http://www.openpermis.org/BSDlicenceKent.txt
 9  
  */
 10  
 package org.openpermis.editor.policy;
 11  
 
 12  
 import java.io.File;
 13  
 import java.io.IOException;
 14  
 import java.io.InputStream;
 15  
 import java.net.URL;
 16  
 import java.util.Enumeration;
 17  
 import java.util.Properties;
 18  
 
 19  
 import javax.swing.JFileChooser;
 20  
 import javax.swing.JOptionPane;
 21  
 
 22  
 import org.jdesktop.application.Action;
 23  
 import org.jdesktop.application.ApplicationActionMap;
 24  
 import org.jdesktop.application.ResourceMap;
 25  
 import org.jdesktop.application.SingleFrameApplication;
 26  
 import org.picocontainer.MutablePicoContainer;
 27  
 import org.picocontainer.PicoBuilder;
 28  
 import org.picocontainer.PicoContainer;
 29  
 import org.slf4j.Logger;
 30  
 import org.slf4j.LoggerFactory;
 31  
 
 32  
 import org.openpermis.editor.policy.adapter.BasicAdapterTrader;
 33  
 import org.openpermis.editor.policy.gui.PolicyIconRegistry;
 34  
 import org.openpermis.editor.policy.view.PolicyView;
 35  
 
 36  
 /**
 37  
  * The singleton policy editor application instance.
 38  
  * <p>In addition to the usual {@link org.jdesktop.application.Application} responsibilities
 39  
  * the policy editor application instance manages the persistent application state.</p>
 40  
  * @since 0.1.0
 41  
  */
 42  0
 public class Application
 43  
         extends SingleFrameApplication
 44  
 {
 45  
 
 46  
         //---- Static
 47  
 
 48  
         /**
 49  
          * The logger object of this class.
 50  
          * @since 0.1.0
 51  
          */
 52  0
         private static final Logger LOGGER =
 53  
                 LoggerFactory.getLogger(Application.class);
 54  
 
 55  
         /**
 56  
          * Name of the file that holds the persistent application state.
 57  
          * @since 0.1.0
 58  
          */
 59  
         private static final String APPLICATION_STATE = "state.xml";
 60  
 
 61  
         /**
 62  
          * The classpath location of the version property file.
 63  
          * @since 0.3.0
 64  
          */
 65  
         private static final String VERSION_FILE = "version.properties";
 66  
 
 67  
         /**
 68  
          * The version file module name of the editor.
 69  
          * <p>This is used to identify the versioning file for the editor.</p>
 70  
          * @since 0.3.0
 71  
          */
 72  
         private static final String VERSION_APPLICATION = "openpermis";
 73  
 
 74  
         /**
 75  
          * Returns the singleton policy editor application instance.
 76  
          * @return the singleton policy editor application instance.
 77  
          * @since 0.1.0
 78  
          */
 79  
         public static synchronized Application getInstance () {
 80  0
                 return Application.class.cast(org.jdesktop.application.Application.getInstance());
 81  
         }
 82  
 
 83  
 
 84  
         //---- State
 85  
 
 86  
         /**
 87  
          * The dependency injection container of this application.
 88  
          * @see #createContainer(Object...)
 89  
          * @since 0.1.0
 90  
          */
 91  
         private PicoContainer container;
 92  
 
 93  
         /**
 94  
          * The persistent state of this application.
 95  
          * @see #getApplicationState()
 96  
          * @see #shutdown()
 97  
          * @since 0.1.0
 98  
          */
 99  
         private ApplicationState state;
 100  
 
 101  
         //---- Methods
 102  
 
 103  
         /**
 104  
          * Returns the context resource map of this class.
 105  
          * @return the context resource map of this class.
 106  
          * @since 0.1.0
 107  
          */
 108  
         private ResourceMap getResourceMap () {
 109  0
                 return getContext().getResourceMap(Application.class);
 110  
         }
 111  
 
 112  
         /**
 113  
          * Returns the context application action map of this class.
 114  
          * @return the context application action map of this class.
 115  
          * @since 0.1.0
 116  
          */
 117  
         private ApplicationActionMap getActionMap () {
 118  0
                 return getContext().getActionMap(Application.class, this);
 119  
         }
 120  
 
 121  
         /**
 122  
          * Reads the version properties of the editor.
 123  
          * <p>The array returned will contain the master version, the build number and date.</p>
 124  
          * @return the version property array, {@code null} if no versioning information is available.
 125  
          * @since 0.3.0
 126  
          */
 127  
         private String[] readVersionProperties () {
 128  
                 try {
 129  0
                         final Enumeration<URL> versionFiles = 
 130  
                                 Application.class.getClassLoader().getResources(VERSION_FILE);
 131  0
                         while (versionFiles.hasMoreElements()) {
 132  0
                                 final URL versionFile = versionFiles.nextElement();
 133  0
                                 final Properties p = new Properties();
 134  
                                 try {
 135  0
                                         final InputStream is = versionFile.openStream();
 136  0
                                         if (is != null) {
 137  0
                                                 p.load(is);
 138  0
                                                 if (VERSION_APPLICATION.equals(p.getProperty("version.application"))) {
 139  0
                                                         final String master = p.getProperty("version.master");
 140  0
                                                         final String build = p.getProperty("version.build");
 141  0
                                                         final String date = p.getProperty("version.date");
 142  0
                                                         return new String[] {
 143  
                                                                 master == null ? "?" : master.trim(),
 144  
                                                                 build == null ? "?" : build.trim(),
 145  
                                                                 date == null ? "?" : date.trim()
 146  
                                                         };
 147  
                                                 }
 148  
                                         }
 149  0
                                 } catch (IOException e) {
 150  0
                                         LOGGER.debug("Cannot parse version file [" + versionFile + "].", e);
 151  0
                                 }
 152  0
                         }
 153  0
                 } catch (Exception e) {
 154  0
                         LOGGER.debug("Excepted while reading versioning properties.", e);
 155  0
                 }
 156  0
                 return null;
 157  
         }
 158  
         
 159  
         /**
 160  
          * Displays the application about box.
 161  
          * @since 0.1.0
 162  
          */
 163  
         @Action
 164  
         public void about () {
 165  0
                 final Object[] versionProperties = readVersionProperties();
 166  0
                 final String aboutText = "About.text" + (versionProperties == null ? ".noVersion" : "");
 167  0
                 final String aboutTitle = "About.title" + (versionProperties == null ? ".noVersion" : "");
 168  0
                 final Object[] args = versionProperties == null ? new Object[0] : versionProperties;
 169  0
                 JOptionPane.showMessageDialog(
 170  
                         getMainFrame(),
 171  
                         getResourceMap().getString(aboutText, args),
 172  
                         getResourceMap().getString(aboutTitle, args),
 173  
                         JOptionPane.PLAIN_MESSAGE,
 174  
                         getResourceMap().getIcon("About.icon")
 175  
                 );
 176  0
         }
 177  
 
 178  
         /**
 179  
          * Action wrapper for the application exit.
 180  
          * @since 0.1.0
 181  
          */
 182  
         @Action
 183  
         public void quit () {
 184  0
                 exit();
 185  0
         }
 186  
 
 187  
         /**
 188  
          * Opens the file chooser and returns the user selection.
 189  
          * <p>The file chooser is displayed as dialog with the application frame
 190  
          * as parent and will use the specified file chooser type.</p>
 191  
          * @param type the file chooser type, either {@link JFileChooser#OPEN_DIALOG} or
 192  
          * {@link JFileChooser#SAVE_DIALOG}.
 193  
          * @param addToRecentFiles wether to add current file to the recent files list.
 194  
          * @param filter file filter, possibly null.
 195  
          * @return the file chosen or <code>null</code> if the user cancelled.
 196  
          * @since 0.1.0
 197  
          */
 198  
         public File chooseFile (int type, boolean addToRecentFiles, PolicyFileFilter filter) {
 199  
 
 200  
                 // create chooser
 201  0
                 final JFileChooser chooser = new JFileChooser();
 202  0
                 chooser.setCurrentDirectory(getApplicationState().getWorkingDirectoryFile());
 203  0
                 chooser.setDialogType(type);
 204  0
                 chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
 205  
 
 206  
                 // set chooser filter
 207  0
                 if (filter != null) {
 208  0
                         chooser.setFileFilter(filter);
 209  
                 }
 210  
 
 211  
                 // handle chooser result
 212  0
                 if (chooser.showDialog(getMainFrame(), null) == JFileChooser.APPROVE_OPTION) {
 213  0
                         final File file = chooser.getSelectedFile();
 214  0
                         getApplicationState().setWorkingDirectoryFile(file);
 215  0
                         if (addToRecentFiles && file.isFile()) {
 216  0
                                 getApplicationState().addRecentFiles(file.getAbsolutePath());
 217  
                         }
 218  0
                         return file;
 219  
                 }
 220  
 
 221  
                 // return
 222  0
                 return null;
 223  
         }
 224  
 
 225  
         /**
 226  
          * Loads the persistent application state.
 227  
          * @return the application state or a default state if there is either no
 228  
          * application state or there is an error reading the state.
 229  
          * @since 0.1.0
 230  
          */
 231  
         private ApplicationState loadApplicationState () {
 232  0
                 ApplicationState appState = null;
 233  
                 try {
 234  0
                         appState = (ApplicationState) getContext().getLocalStorage().load(APPLICATION_STATE);
 235  0
                 } catch (Exception e) {
 236  0
                         LOGGER.warn("Application state could not be loaded.", e);
 237  0
                 }
 238  0
                 if (appState == null) {
 239  0
                         appState = new ApplicationState();
 240  0
                         LOGGER.debug("Creating default application state [{}].", appState);
 241  
                 } else {
 242  0
                         LOGGER.debug("Application state loaded [{}].", appState);
 243  
                 }
 244  0
                 return appState;
 245  
         }
 246  
 
 247  
         /**
 248  
          * Stores the application state persistently in the application state file.
 249  
          * <p>Errors while storing the application state are ignored.
 250  
          * @param appState the state to store.
 251  
          * @since 0.1.0
 252  
          */
 253  
         private void storeApplicationState (ApplicationState appState) {
 254  
                 try {
 255  0
                         LOGGER.debug("Storing application state [{}].", appState);
 256  0
                         getContext().getLocalStorage().save(appState, APPLICATION_STATE);
 257  0
                 } catch (IOException e) {
 258  0
                         LOGGER.warn("Application state could not be stored.", e);
 259  0
                 }
 260  0
         }
 261  
 
 262  
         /**
 263  
          * Returns the application state.
 264  
          * <p>The state is lazily loaded or initialized on first use.</p>
 265  
          * @return the application state requested.
 266  
          * @since 0.1.0
 267  
          */
 268  
         public synchronized ApplicationState getApplicationState () {
 269  0
                 if (this.state == null) {
 270  0
                         this.state = loadApplicationState();
 271  
                 }
 272  0
                 return this.state;
 273  
         }
 274  
 
 275  
         /**
 276  
          * Creates and configures the pico container for this application.
 277  
          * @param components an array of components to add.
 278  
          * @return the dependency injection container for this application.
 279  
          * @since 0.1.0
 280  
          * @since 0.3.0 added components.
 281  
          */
 282  
         private final PicoContainer createContainer (Object... components) {
 283  0
                 final MutablePicoContainer pico = new PicoBuilder().build();
 284  0
                 pico.addComponent(Application.class, this);
 285  0
                 pico.addComponent(getContext());
 286  0
                 pico.addComponent(PolicyView.class);
 287  0
                 pico.addComponent(BasicAdapterTrader.class);
 288  0
                 pico.addAdapter(new FrameInjector());
 289  0
                 for (Object component : components) {
 290  0
                         pico.addComponent(component);
 291  
                 }
 292  0
                 return pico;
 293  
         }
 294  
 
 295  
         //---- Application
 296  
 
 297  
         /**
 298  
          * @since 0.1.0
 299  
          */
 300  
         @Override
 301  
         protected void initialize (final String[] args) {
 302  0
                 LOGGER.debug("Initializing application.");
 303  0
                 super.initialize(args);
 304  0
                 if (MacAdapter.isMac()) {
 305  0
                         final MacAdapter adapter = new MacAdapter();
 306  0
                         adapter.registerAboutAction(getActionMap().get("about"));
 307  0
                         adapter.registerPreferencesAction(getActionMap().get("preferences"));
 308  0
                         adapter.registerQuitAction(getActionMap().get("quit"));
 309  0
                         adapter.setDockImage(getResourceMap().getImageIcon("About.icon").getImage());
 310  
                 }
 311  0
                 this.container = createContainer(PolicyIconRegistry.create(getContext()));
 312  0
         }
 313  
 
 314  
         /**
 315  
          * @since 0.1.0
 316  
          */
 317  
         @Override
 318  
         protected void shutdown () {
 319  0
                 LOGGER.debug("Terminating application.");
 320  0
                 storeApplicationState(getApplicationState());
 321  0
                 LOGGER.debug("Shutdown complete.");
 322  0
                 super.shutdown();
 323  0
         }
 324  
 
 325  
         /**
 326  
          * @since 0.1.0
 327  
          */
 328  
         @Override
 329  
         protected void startup () {
 330  0
                 LOGGER.debug("Starting application.");
 331  0
                 final PolicyView policyView = this.container.getComponent(PolicyView.class);
 332  0
                 show(policyView.configure(getMainView()));
 333  0
         }
 334  
 
 335  
 }