/**
* ***************************************************************************
* Copyright (c) 2010 Qcadoo Limited
* Project: Qcadoo Framework
* Version: 1.4
*
* This file is part of Qcadoo.
*
* Qcadoo is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation; either version 3 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* ***************************************************************************
*/
package com.qcadoo.plugin.internal;
import com.qcadoo.plugin.api.*;
import com.qcadoo.plugin.internal.api.InternalPlugin;
import com.qcadoo.tenant.api.MultiTenantUtil;
import java.util.*;
import static com.qcadoo.plugin.api.PluginState.*;
import static java.util.Collections.*;
public final class DefaultPlugin implements InternalPlugin {
private final Map<ModuleFactory<?>, List<Module>> modulesByFactories;
private final List<ModuleFactory<?>> factories;
private final List<ModuleFactory<?>> reversedFactories;
private final PluginInformation information;
private final Set<PluginDependencyInformation> dependencies;
private final boolean system;
private final String identifier;
private final Version version;
private final String fileName;
private PluginState state;
private DefaultPlugin(final String identifier, final String fileName, final boolean system, final Version version,
final List<ModuleFactory<?>> factories, final Map<ModuleFactory<?>, List<Module>> modulesByFactories,
final PluginInformation information, final Set<PluginDependencyInformation> dependencies) {
this.state = UNKNOWN;
this.identifier = identifier;
this.fileName = fileName;
this.version = version;
this.modulesByFactories = modulesByFactories;
this.information = information;
this.dependencies = dependencies;
this.system = system;
this.factories = factories;
this.reversedFactories = new ArrayList<>(factories);
Collections.reverse(reversedFactories);
}
@Override
public PluginInformation getPluginInformation() {
return information;
}
@Override
public Set<PluginDependencyInformation> getRequiredPlugins() {
return dependencies;
}
@Override
public boolean isSystemPlugin() {
return system;
}
@Override
public void changeStateTo(final PluginState targetState) {
if (!isTransitionPossible(getState(), targetState)) {
throw new IllegalStateException("Cannot change state of plugin " + this + " from " + getState() + " to "
+ targetState);
}
if (hasState(UNKNOWN)) {
state = targetState;
return;
}
Plugin thisPlugin = this;
if (ENABLED.equals(targetState)) {
state = targetState;
for (final ModuleFactory<?> factory : factories) {
List<Module> modules = modulesByFactories.get(factory);
for (final Module module : modules) {
module.enable();
MultiTenantUtil.doInMultiTenantContext(() -> {
if (PluginUtils.isEnabled(thisPlugin)) {
module.multiTenantEnable();
}
});
}
}
} else if (DISABLED.equals(targetState)) {
for (final ModuleFactory<?> factory : reversedFactories) {
List<Module> modules = modulesByFactories.get(factory);
Collections.reverse(modules);
for (final Module module : modules) {
module.disable();
MultiTenantUtil.doInMultiTenantContext(() -> {
if (PluginUtils.isEnabled(thisPlugin)) {
module.multiTenantDisable();
}
});
}
}
state = targetState;
} else {
state = targetState;
}
}
private boolean isTransitionPossible(final PluginState from, final PluginState to) {
if (from == null || to == null || to.equals(UNKNOWN) || to.equals(from)) {
return false;
}
if (from.equals(UNKNOWN)) {
return true;
}
if (to.equals(TEMPORARY)) {
return false;
}
if (from.equals(ENABLING) && to.equals(DISABLED)) {
return false;
}
if (from.equals(ENABLED) && to.equals(ENABLING)) {
return false;
}
if (from.equals(TEMPORARY) && !to.equals(ENABLING)) {
return false;
}
return true;
}
@Override
public String getFilename() {
return fileName;
}
@Override
public int compareVersion(final Version version) {
return this.version.compareTo(version);
}
@Override
public List<Module> getModules(final ModuleFactory<?> moduleFactory) {
if (modulesByFactories.containsKey(moduleFactory)) {
return modulesByFactories.get(moduleFactory);
} else {
return Collections.emptyList();
}
}
public static class Builder {
private final String identifier;
private String fileName;
private Version version;
private String description;
private String vendor;
private String vendorUrl;
private String name;
private String license;
private boolean system;
private String group;
private final Map<ModuleFactory<?>, List<Module>> modulesByFactories = new LinkedHashMap<>();
private final Set<PluginDependencyInformation> dependencyInformations = new HashSet<>();
private final List<ModuleFactory<?>> factories;
public Builder(final String identifier, final List<ModuleFactory<?>> factories) {
this.identifier = identifier;
this.factories = factories;
for (ModuleFactory<?> factory : factories) {
modulesByFactories.put(factory, new ArrayList<>());
}
}
public static Builder identifier(final String identifier, final List<ModuleFactory<?>> factories) {
return new Builder(identifier, factories);
}
public Builder withFileName(final String fileName) {
this.fileName = fileName;
return this;
}
public Builder withModule(final ModuleFactory<?> moduleFactory, final Module module) {
modulesByFactories.get(moduleFactory).add(module);
return this;
}
public Builder withVersion(final String version) {
this.version = new Version(version);
return this;
}
public Builder withDependency(final String identifier, final String version) {
dependencyInformations.add(new PluginDependencyInformation(identifier, new VersionOfDependency(version)));
return this;
}
public Builder withFeature(final String featureName, final String systemName) {
// TODO KRNA add features
return this;
}
public Builder withName(final String name) {
this.name = name;
return this;
}
public Builder withDescription(final String description) {
this.description = description;
return this;
}
public Builder withVendor(final String vendor) {
this.vendor = vendor;
return this;
}
public Builder withVendorUrl(final String vendorUrl) {
this.vendorUrl = vendorUrl;
return this;
}
public Builder withLicense(final String license) {
this.license = license;
return this;
}
public Builder asSystem() {
this.system = true;
return this;
}
public Builder withGroup(final String group){
this.group = group;
return this;
}
public InternalPlugin build() {
PluginInformation pluginInformation = new PluginInformation(name, description, vendor, vendorUrl, license, group);
return new DefaultPlugin(identifier, fileName, system, version, unmodifiableList(factories),
unmodifiableMap(modulesByFactories), pluginInformation, unmodifiableSet(dependencyInformations));
}
}
@Override
public String getIdentifier() {
return identifier;
}
@Override
public Version getVersion() {
return version;
}
@Override
public PluginState getState() {
return state;
}
@Override
public boolean hasState(final PluginState expectedState) {
return state.equals(expectedState);
}
@Override
public int hashCode() {
int prime = 31;
int result = 1;
result = prime * result + ((identifier == null) ? 0 : identifier.hashCode());
result = prime * result + ((fileName == null) ? 0 : fileName.hashCode());
result = prime * result + ((state == null) ? 0 : state.hashCode());
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof DefaultPlugin)) {
return false;
}
DefaultPlugin other = (DefaultPlugin) obj;
if (identifier == null) {
if (other.identifier != null) {
return false;
}
} else if (!identifier.equals(other.identifier)) {
return false;
}
if (fileName == null) {
if (other.fileName != null) {
return false;
}
} else if (!fileName.equals(other.fileName)) {
return false;
}
if (state != other.state) {
return false;
}
if (version == null) {
if (other.version != null) {
return false;
}
} else if (!version.equals(other.version)) {
return false;
}
return true;
}
@Override
public String toString() {
return "DefaultPlugin [identifier=" + identifier + ", version=" + version + ", state=" + state + ", system=" + system
+ "]";
}
}