Coverage Report - org.jtheque.core.managers.module.ModuleManager
 
Classes in this File Line Coverage Branch Coverage Complexity
ModuleManager
0 %
0/151
0 %
0/70
2.147
 
 1  
 package org.jtheque.core.managers.module;
 2  
 
 3  
 /*
 4  
  * This file is part of JTheque.
 5  
  *
 6  
  * JTheque is free software: you can redistribute it and/or modify
 7  
  * it under the terms of the GNU General Public License as published by
 8  
  * the Free Software Foundation, either version 3 of the License.
 9  
  *
 10  
  * JTheque is distributed in the hope that it will be useful,
 11  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13  
  * GNU General Public License for more details.
 14  
  *
 15  
  * You should have received a copy of the GNU General Public License
 16  
  * along with JTheque.  If not, see <http://www.gnu.org/licenses/>.
 17  
  */
 18  
 
 19  
 import org.jtheque.core.managers.AbstractManager;
 20  
 import org.jtheque.core.managers.Managers;
 21  
 import org.jtheque.core.managers.beans.IBeansManager;
 22  
 import org.jtheque.core.managers.error.JThequeError;
 23  
 import org.jtheque.core.managers.language.ILanguageManager;
 24  
 import org.jtheque.core.managers.module.annotations.Module;
 25  
 import org.jtheque.core.managers.module.beans.CollectionBasedModule;
 26  
 import org.jtheque.core.managers.module.beans.EmptyBeanMethod;
 27  
 import org.jtheque.core.managers.module.beans.ModuleContainer;
 28  
 import org.jtheque.core.managers.module.beans.ModuleState;
 29  
 import org.jtheque.core.managers.module.loaders.IModuleLoader;
 30  
 import org.jtheque.core.managers.module.loaders.ModuleLoader;
 31  
 import org.jtheque.core.managers.update.IUpdateManager;
 32  
 import org.jtheque.core.managers.update.InstallationResult;
 33  
 import org.jtheque.core.managers.update.repository.ModuleDescription;
 34  
 import org.jtheque.core.managers.update.repository.Repository;
 35  
 import org.jtheque.core.managers.update.repository.RepositoryReader;
 36  
 import org.jtheque.core.managers.view.able.IViewManager;
 37  
 import org.jtheque.utils.StringUtils;
 38  
 import org.jtheque.utils.bean.Version;
 39  
 import org.jtheque.utils.collections.CollectionUtils;
 40  
 import org.jtheque.utils.io.FileUtils;
 41  
 
 42  
 import javax.annotation.Resource;
 43  
 import java.io.File;
 44  
 import java.util.ArrayList;
 45  
 import java.util.Collection;
 46  
 import java.util.List;
 47  
 
 48  
 /**
 49  
  * A module manager implementation. It manage the cycle life of the modules.
 50  
  *
 51  
  * @author Baptiste Wicht
 52  
  */
 53  0
 public final class ModuleManager extends AbstractManager implements IModuleManager {
 54  
     /**
 55  
      * The application repository.
 56  
      */
 57  
     private Repository repository;
 58  
 
 59  
     /**
 60  
      * The module who needs collection choices, if there is one.
 61  
      */
 62  
     private CollectionBasedModule collectionModule;
 63  
 
 64  
     /**
 65  
      * The configuration of the module manager. It seems the informations about the modules who're
 66  
      * installed or disabled.
 67  
      */
 68  
     private ModuleConfiguration configuration;
 69  
 
 70  
     @Resource
 71  
     private IModuleLoader moduleLoader;
 72  
 
 73  0
     private final List<ModuleContainer> moduleContainers = new ArrayList<ModuleContainer>(10);
 74  0
     private final Collection<ModuleContainer> modulesToLoad = new ArrayList<ModuleContainer>(10);
 75  
 
 76  
     /**
 77  
      * Indicate if we must refresh the list of the modules to load.
 78  
      */
 79  0
     private boolean mustRefresh = true;
 80  
 
 81  
     @Override
 82  
     public void preInit() {
 83  0
         moduleContainers.addAll(ModuleLoader.getModules());
 84  
 
 85  0
         loadModuleBeans();
 86  
 
 87  0
         for (JThequeError error : ModuleLoader.getErrors()) {
 88  0
             Managers.getManager(IViewManager.class).displayError(error);
 89  
         }
 90  0
     }
 91  
 
 92  
     /**
 93  
      * Load the module beans.
 94  
      */
 95  
     private void loadModuleBeans() {
 96  0
         for (ModuleContainer module : moduleContainers) {
 97  0
             module.setModule(Managers.getManager(IBeansManager.class).getBean(module.getBeanName()));
 98  
 
 99  0
             Managers.getManager(ILanguageManager.class).addBaseName(module.getInfos().i18n());
 100  
 
 101  0
             if (CollectionBasedModule.class.isAssignableFrom(module.getModule().getClass())) {
 102  0
                 collectionModule = (CollectionBasedModule) module.getModule();
 103  
             }
 104  
         }
 105  0
     }
 106  
 
 107  
     @Override
 108  
     public void close() {
 109  0
         for (ModuleContainer module : moduleContainers) {
 110  0
             if (module.getState() == ModuleState.UNINSTALLED) {
 111  0
                 configuration.remove(module);
 112  
 
 113  
                 //We create a "tag" (a file) to say to the application to delete it at the next launch
 114  0
                 FileUtils.createEmptyFile(
 115  
                         module.getModuleFile().getAbsolutePath().replace(
 116  
                                 module.getModuleFile().getName(),
 117  
                                 "deleted" + module.getModuleFile().getName()));
 118  
             }
 119  
         }
 120  0
     }
 121  
     
 122  
     @Override
 123  
     public void prePlugModules() {
 124  0
         configureModules();
 125  
 
 126  0
         for (ModuleContainer module : getModulesToLoad()) {
 127  0
             module.getPrePlugMethod().run();
 128  0
             setState(module, ModuleState.LOADED);
 129  
         }
 130  0
     }
 131  
 
 132  
     /**
 133  
      * Plug the modules.
 134  
      */
 135  
     @Override
 136  
     public void plugModules() {
 137  0
         for (ModuleContainer module : getModulesToLoad()) {
 138  0
             module.getPlugMethod().run();
 139  
         }
 140  0
     }
 141  
 
 142  
     /**
 143  
      * Return the modules to load.
 144  
      *
 145  
      * @return A List containing all the modules to load.
 146  
      */
 147  
     private Collection<ModuleContainer> getModulesToLoad() {
 148  0
         if (mustRefresh) {
 149  0
             modulesToLoad.clear();
 150  
 
 151  0
             addLoadableModules();
 152  
 
 153  0
             mustRefresh = false;
 154  
         }
 155  
 
 156  0
         return modulesToLoad;
 157  
     }
 158  
 
 159  
     /**
 160  
      * Add the loadable modules to the modules to load list.
 161  
      */
 162  
     private void addLoadableModules() {
 163  0
         for (ModuleContainer module : moduleContainers) {
 164  0
             if (canBeLoaded(module) && areAllDependenciesSatisfied(module)) {
 165  0
                 modulesToLoad.add(module);
 166  
             }
 167  
         }
 168  0
     }
 169  
 
 170  
     /**
 171  
      * Test if the module can be loaded.
 172  
      *
 173  
      * @param module The module to test.
 174  
      * @return true if the module can be loaded else false.
 175  
      */
 176  
     private static boolean canBeLoaded(ModuleContainer module) {
 177  0
         return !(module.getState() == ModuleState.DISABLED || module.getState() == ModuleState.UNINSTALLED);
 178  
     }
 179  
 
 180  
     /**
 181  
      * Return the dependency of the module.
 182  
      *
 183  
      * @param module The module to get the dependency from.
 184  
      * @return The dependency of the module or null if the module has no dependency.
 185  
      */
 186  
     private static String[] getDependencies(ModuleContainer module) {
 187  0
         return module.getInfos().dependencies();
 188  
     }
 189  
 
 190  
     /**
 191  
      * Unplug the modules.
 192  
      */
 193  
     @Override
 194  
     public void unplugModules() {
 195  0
         List<ModuleContainer> modulesToUnplug = CollectionUtils.copyOf(getModulesToLoad());
 196  
 
 197  0
         CollectionUtils.reverse(modulesToUnplug);
 198  
 
 199  0
         for (ModuleContainer module : modulesToUnplug) {
 200  0
             if (module.getState() == ModuleState.LOADED) {
 201  0
                 module.getUnPlugMethod().run();
 202  
 
 203  0
                 setState(module, ModuleState.INSTALLED);
 204  
             }
 205  
 
 206  0
             Managers.getManager(ILanguageManager.class).removeBaseName(module.getInfos().i18n());
 207  
         }
 208  0
     }
 209  
 
 210  
     /**
 211  
      * Configure the modules.
 212  
      */
 213  
     private void configureModules() {
 214  0
         configuration = getStates().getState(ModuleConfiguration.class);
 215  
 
 216  0
         if (configuration == null) {
 217  0
             initConfiguration();
 218  
         }
 219  
 
 220  0
         CollectionUtils.filter(moduleContainers, new ConfigurationFilter(configuration));
 221  0
         CollectionUtils.filter(moduleContainers, new CoreVersionFilter());
 222  
 
 223  0
         CollectionUtils.sort(moduleContainers, new ModuleComparator());
 224  0
     }
 225  
 
 226  
     /**
 227  
      * Init the configuration of the modules.
 228  
      */
 229  
     private void initConfiguration() {
 230  
         try {
 231  0
             configuration = getStates().createState(ModuleConfiguration.class);
 232  0
         } catch (Exception e) {
 233  0
             configuration = new ModuleConfiguration();
 234  0
             getLogger().error(e);
 235  0
             getErrorManager().addInternationalizedError("error.loading.configuration");
 236  0
         }
 237  
 
 238  0
         for (ModuleContainer module : moduleContainers) {
 239  0
             configuration.add(module, ModuleState.INSTALLED);
 240  
         }
 241  0
     }
 242  
 
 243  
     @Override
 244  
     public Collection<ModuleContainer> getModules() {
 245  0
         return moduleContainers;
 246  
     }
 247  
 
 248  
     @Override
 249  
     public Collection<ModuleDescription> getModulesFromRepository() {
 250  0
         return getRepository().getModules();
 251  
     }
 252  
 
 253  
     @Override
 254  
     public Repository getRepository() {
 255  0
         if (repository == null) {
 256  0
             repository = new RepositoryReader().read(Managers.getCore().getApplication().getRepository());
 257  
         }
 258  
 
 259  0
         return repository;
 260  
     }
 261  
 
 262  
     /**
 263  
      * Set the state of a module.
 264  
      *
 265  
      * @param module The module to set the state.
 266  
      * @param state  The state.
 267  
      */
 268  
     void setState(ModuleContainer module, ModuleState state) {
 269  0
         module.setState(state);
 270  0
         configuration.setState(module.getId(), state);
 271  0
     }
 272  
 
 273  
     /**
 274  
      * Load a module.
 275  
      *
 276  
      * @param module The module to load.
 277  
      */
 278  
     @Override
 279  
     public void loadModule(ModuleContainer module) {
 280  0
         setState(module, ModuleState.LOADED);
 281  
 
 282  0
         module.getPrePlugMethod().run();
 283  0
         module.getPlugMethod().run();
 284  0
     }
 285  
 
 286  
     @Override
 287  
     public void enableModule(ModuleContainer module) {
 288  0
         setState(module, ModuleState.INSTALLED);
 289  0
     }
 290  
 
 291  
     /**
 292  
      * Disable a module.
 293  
      *
 294  
      * @param module The module to disable.
 295  
      */
 296  
     @Override
 297  
     public void disableModule(ModuleContainer module) {
 298  0
         setState(module, ModuleState.DISABLED);
 299  
 
 300  0
         module.getUnPlugMethod().run();
 301  
 
 302  0
         mustRefresh = true;
 303  0
     }
 304  
 
 305  
     /**
 306  
      * Install a module.
 307  
      *
 308  
      * @param file The file of the module.
 309  
      * @return true if the module has been installed, else false.
 310  
      */
 311  
     @Override
 312  
     public boolean installModule(File file) {
 313  0
         Object module = moduleLoader.installModule(file);
 314  
 
 315  0
         if (module == null) {
 316  0
             return false;
 317  
         }
 318  
 
 319  0
         ModuleContainer container = createSimpleContainer(module);
 320  
 
 321  0
         moduleContainers.add(container);
 322  
 
 323  0
         configuration.add(container);
 324  
 
 325  0
         fireModuleAdded();
 326  
 
 327  0
         return true;
 328  
     }
 329  
 
 330  
     @Override
 331  
     public void install(String versionsFileURL) {
 332  0
         InstallationResult result = Managers.getManager(IUpdateManager.class).install(versionsFileURL);
 333  
 
 334  0
         if (result.isInstalled() && result.isMustRestart()) {
 335  0
             configuration.add(result);
 336  
 
 337  0
             Managers.getManager(IViewManager.class).displayI18nText("message.module.repository.installed.restart");
 338  0
         } else if (result.isInstalled()) {
 339  0
             Object module = moduleLoader.loadModule(new File(
 340  
                     Managers.getCore().getFolders().getModulesFolder(), result.getJarFile()));
 341  
 
 342  0
             ModuleContainer container = createSimpleContainer(module);
 343  
 
 344  0
             moduleContainers.add(container);
 345  
 
 346  0
             configuration.add(result);
 347  
 
 348  0
             fireModuleAdded();
 349  
 
 350  0
             getManager(IViewManager.class).displayI18nText("message.module.repository.installed");
 351  0
         } else {
 352  0
             getManager(IViewManager.class).displayI18nText("error.repository.module.not.installed");
 353  
         }
 354  0
     }
 355  
 
 356  
     /**
 357  
      * Create a simple module container for the module.
 358  
      *
 359  
      * @param module The module.
 360  
      * @return The module container for the specified module.
 361  
      */
 362  
     private static ModuleContainer createSimpleContainer(Object module) {
 363  0
         ModuleContainer container = new ModuleContainer("notABean", module.getClass().getAnnotation(Module.class));
 364  
 
 365  0
         container.setModule(module);
 366  0
         container.setState(ModuleState.JUST_INSTALLED);
 367  0
         container.setPlugMethod(new EmptyBeanMethod());
 368  0
         container.setPrePlugMethod(new EmptyBeanMethod());
 369  0
         container.setUnPlugMethod(new EmptyBeanMethod());
 370  
 
 371  0
         return container;
 372  
     }
 373  
 
 374  
     /**
 375  
      * Uninstall a module.
 376  
      *
 377  
      * @param module The module to uninstall.
 378  
      */
 379  
     @Override
 380  
     public void uninstallModule(ModuleContainer module) {
 381  0
         setState(module, ModuleState.UNINSTALLED);
 382  
 
 383  0
         module.getUnPlugMethod().run();
 384  
 
 385  0
         fireModuleRemoved(module);
 386  0
     }
 387  
 
 388  
     @Override
 389  
     public void addModuleListener(ModuleListener listener) {
 390  0
         getListeners().add(ModuleListener.class, listener);
 391  0
     }
 392  
 
 393  
     @Override
 394  
     public void removeModuleListener(ModuleListener listener) {
 395  0
         getListeners().remove(ModuleListener.class, listener);
 396  0
     }
 397  
 
 398  
     /**
 399  
      * Fire a module added event.
 400  
      */
 401  
     private static void fireModuleAdded() {
 402  0
         ModuleListener[] l = getListeners().getListeners(ModuleListener.class);
 403  
 
 404  0
         for (ModuleListener listener : l) {
 405  0
             listener.moduleAdded();
 406  
         }
 407  0
     }
 408  
 
 409  
     /**
 410  
      * Fire a module removed event.
 411  
      *
 412  
      * @param module The removed module.
 413  
      */
 414  
     private static void fireModuleRemoved(ModuleContainer module) {
 415  0
         ModuleListener[] l = getListeners().getListeners(ModuleListener.class);
 416  
 
 417  0
         for (ModuleListener listener : l) {
 418  0
             listener.moduleRemoved(module);
 419  
         }
 420  0
     }
 421  
 
 422  
     @Override
 423  
     public String canModuleLaunched(ModuleContainer module) {
 424  0
         if (new Version(module.getInfos().core()).isGreaterThan(Managers.getCore().getCoreCurrentVersion())) {
 425  0
             return getMessage("modules.message.versionproblem");
 426  0
         } else if (!areAllDependenciesSatisfied(module)) {
 427  0
             return getMessage("error.module.not.loaded.dependency", module.getInfos().dependencies());
 428  0
         } else if (module.getState() == ModuleState.JUST_INSTALLED) {
 429  0
             return getMessage("error.module.just.installed");
 430  
         }
 431  
 
 432  0
         return "";
 433  
     }
 434  
 
 435  
     /**
 436  
      * Indicate if all the dependencies of the module are satisfied.
 437  
      *
 438  
      * @param module The module to test.
 439  
      * @return <code>true</code> if all the dependencies are satisfied else <code>false</code>.
 440  
      */
 441  
     private boolean areAllDependenciesSatisfied(ModuleContainer module) {
 442  0
         if (StringUtils.isEmpty(getDependencies(module))) {
 443  0
             return true;
 444  
         }
 445  
 
 446  0
         for (String dependency : getDependencies(module)) {
 447  0
             ModuleContainer resolvedDependency = getModuleById(dependency);
 448  
 
 449  0
             if (resolvedDependency == null || !canBeLoaded(resolvedDependency)) {
 450  0
                 return false;
 451  
             }
 452  
         }
 453  
 
 454  0
         return true;
 455  
     }
 456  
 
 457  
     @Override
 458  
     public ModuleContainer getModuleById(String id) {
 459  0
         ModuleContainer module = null;
 460  
 
 461  0
         for (ModuleContainer m : moduleContainers) {
 462  0
             if (id.equals(m.getInfos().id())) {
 463  0
                 module = m;
 464  0
                 break;
 465  
             }
 466  
         }
 467  
 
 468  0
         return module;
 469  
     }
 470  
 
 471  
     @Override
 472  
     public boolean isInstalled(String module) {
 473  0
         return getModuleById(module) != null;
 474  
     }
 475  
 
 476  
     @Override
 477  
     public boolean isCollectionModule() {
 478  0
         return collectionModule != null;
 479  
     }
 480  
 
 481  
     @Override
 482  
     public boolean chooseCollection(String collection, String password, boolean create) {
 483  0
         return collectionModule.chooseCollection(collection, password, create);
 484  
     }
 485  
 
 486  
     @Override
 487  
     public void plugCollection() {
 488  0
         collectionModule.plugCollection();
 489  0
     }
 490  
 }