/**
* This file Copyright (c) 2003-2012 Magnolia International
* Ltd. (http://www.magnolia-cms.com). All rights reserved.
*
*
* This file is dual-licensed under both the Magnolia
* Network Agreement and the GNU General Public License.
* You may elect to use one or the other of these licenses.
*
* This file is distributed in the hope that it will be
* useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
* Redistribution, except as permitted by whichever of the GPL
* or MNA you select, is prohibited.
*
* 1. For the GPL license (GPL), you can redistribute and/or
* modify this file under the terms of the GNU General
* Public License, Version 3, as published by the Free Software
* Foundation. You should have received a copy of the GNU
* General Public License, Version 3 along with this program;
* if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* 2. For the Magnolia Network Agreement (MNA), this file
* and the accompanying materials are made available under the
* terms of the MNA which accompanies this distribution, and
* is available at http://www.magnolia-cms.com/mna.html
*
* Any modifications to this file must keep this entire header
* intact.
*
*/
package info.magnolia.module;
import info.magnolia.module.model.ModuleDefinition;
import info.magnolia.module.model.Version;
import info.magnolia.module.ui.ModuleManagerUI;
import info.magnolia.module.delta.Delta;
import info.magnolia.module.delta.DeltaType;
import info.magnolia.objectfactory.Components;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* ModuleManager is responsible for the lifecycle of modules.
* (loads definitions, install/update/uninstall, start/stop)
*
* @author gjoseph
* @version $Revision: $ ($Author: $)
*/
public interface ModuleManager {
/**
* Loads modules definitions, validates dependencies and sorts modules
* by dependencies.
*
* TODO - this should not be done by ModuleManager
*/
List<ModuleDefinition> loadDefinitions() throws ModuleManagementException;
/**
* Checks if we need to do any module installation, update or uninstall.
*/
void checkForInstallOrUpdates() throws ModuleManagementException;
/**
* Returns the status as discovered by checkForInstallOrUpdates().
* @throws IllegalStateException if checkForInstallOrUpdates was never called.
*/
ModuleManagementState getStatus();
ModuleManagerUI getUI();
void performInstallOrUpdate();
InstallContext getInstallContext();
void startModules();
void stopModules();
/**
* Use this to retrieve the configured singleton impl of ModuleManager.
* @deprecated since 4.5, use IoC.
*/
public class Factory {
/**
* @deprecated since 4.5, use IoC.
*/
public static ModuleManager getInstance() {
return Components.getSingleton(ModuleManager.class);
}
}
/**
* Represent what's to be done for all modules.
*/
public final static class ModuleManagementState {
private final List<ModuleAndDeltas> list;
private EnumSet<DeltaType> cachedDeltaTypes;
public ModuleManagementState() {
this.list = new ArrayList<ModuleAndDeltas>();
}
public boolean needsUpdateOrInstall() {
return !(list.isEmpty());
}
void addModule(ModuleDefinition module, Version currentVersion, List<Delta> deltas) {
list.add(new ModuleAndDeltas(module, currentVersion, deltas));
}
public List<ModuleAndDeltas> getList() {
return list;
}
/**
* Returns one of the given Strings depending on the combination of delta types
* in the registered deltas. Typical use:
* <code>
* getDeltaTypesDescription({"modules need to be installed", "modules need to be installed", "modules need to be installed or updated"});
* </code>
* @param texts
* @return
*/
public String getDeltaTypesDescription(String[] texts) {
if (texts == null || texts.length != 3) {
throw new IllegalStateException("Please pass an array of 3 strings.");
}
// we can cache this, since this method is only used after all modules' deltas have been registered.
if (cachedDeltaTypes == null) {
cachedDeltaTypes = getDeltaTypes();
}
if (cachedDeltaTypes.size() == 1) {
if (cachedDeltaTypes.contains(DeltaType.install)) {
return texts[0];
} else if (cachedDeltaTypes.contains(DeltaType.update)) {
return texts[1];
}
} else if (cachedDeltaTypes.size() == 2) {
if (cachedDeltaTypes.containsAll(EnumSet.<DeltaType>of(DeltaType.install, DeltaType.update))) {
return texts[2];
}
}
throw new IllegalStateException("Unhandled delta types combination: " + cachedDeltaTypes);
}
protected EnumSet<DeltaType> getDeltaTypes() {
if (list.isEmpty()) {
throw new IllegalStateException("No registered deltas");
}
final Set<DeltaType> types = new HashSet<DeltaType>();
for (ModuleAndDeltas moduleAndDeltas : list) {
for (Delta delta : moduleAndDeltas.getDeltas()) {
types.add(delta.getType());
}
}
return EnumSet.copyOf(types);
}
}
/**
* Represents what's to be done for each module.
*/
public final static class ModuleAndDeltas {
private final ModuleDefinition module;
private final Version currentVersion;
private final List<Delta> deltas;
public ModuleAndDeltas(ModuleDefinition module, Version currentVersion, List<Delta> deltas) {
this.module = module;
this.currentVersion = currentVersion;
this.deltas = deltas;
}
public ModuleDefinition getModule() {
return module;
}
public Version getCurrentVersion() {
return currentVersion;
}
public List<Delta> getDeltas() {
return deltas;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("ModuleAndDeltas for ");
sb.append(module.getName());
if (currentVersion != null) {
sb.append(": current version is ");
sb.append(currentVersion);
sb.append(", updating to ");
} else {
sb.append(": installing version ");
}
sb.append(module.getVersion());
sb.append(" with ");
sb.append(deltas.size());
sb.append(" deltas.");
return sb.toString();
}
}
}