/*
* Copyright 2015 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.terasology.module;
import com.google.common.base.Preconditions;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.collect.Table;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.naming.Name;
import org.terasology.naming.Version;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* Implementation of ModuleRegistry based around a com.google.common.collect.Table.
*
* @author Immortius
*/
public class TableModuleRegistry implements ModuleRegistry {
private static final Logger logger = LoggerFactory.getLogger(TableModuleRegistry.class);
private final Table<Name, Version, Module> modules = HashBasedTable.create();
private final Map<Name, Module> latestModules = Maps.newHashMap();
@Override
public boolean add(Module module) {
Preconditions.checkNotNull(module);
if (!modules.contains(module.getId(), module.getVersion())) {
modules.put(module.getId(), module.getVersion(), module);
Module previousLatest = latestModules.get(module.getId());
if (previousLatest == null || previousLatest.getVersion().compareTo(module.getVersion()) <= 0) {
latestModules.put(module.getId(), module);
}
return true;
} else {
logger.error("Module {}-{} already registered from {}, cannot register same module from {}",
module.getId(),
module.getVersion(),
modules.get(module.getId(), module.getVersion()).getLocations(),
module.getLocations());
}
return false;
}
@Override
public boolean remove(Object o) {
if (o instanceof Module) {
Module module = (Module) o;
if (modules.remove(module.getId(), module.getVersion()) != null) {
Module latest = latestModules.get(module.getId());
if (latest.getVersion().compareTo(module.getVersion()) == 0) {
updateLatestFor(module.getId());
}
return true;
}
return false;
}
return false;
}
private void updateLatestFor(Name moduleId) {
Module newLatest = null;
for (Module remainingModule : modules.row(moduleId).values()) {
if (newLatest == null || remainingModule.getVersion().compareTo(newLatest.getVersion()) > 0) {
newLatest = remainingModule;
}
}
if (newLatest != null) {
latestModules.put(moduleId, newLatest);
} else {
latestModules.remove(moduleId);
}
}
@Override
public boolean removeAll(Collection<?> c) {
boolean result = false;
for (Object o : c) {
result |= remove(o);
}
return result;
}
@Override
public boolean addAll(Collection<? extends Module> c) {
boolean result = false;
for (Object o : c) {
if (o instanceof Module) {
result |= add((Module) o);
}
}
return result;
}
@Override
public boolean retainAll(Collection<?> c) {
Set<Module> modulesToRetain = Sets.newHashSet();
for (Object o : c) {
if (o instanceof Module) {
modulesToRetain.add((Module) o);
}
}
boolean changed = false;
Iterator<Module> moduleIterator = modules.values().iterator();
while (moduleIterator.hasNext()) {
Module next = moduleIterator.next();
if (!modulesToRetain.contains(next)) {
moduleIterator.remove();
changed = true;
}
}
if (changed) {
for (Name name : modules.rowKeySet()) {
updateLatestFor(name);
}
}
return changed;
}
@Override
public Set<Name> getModuleIds() {
return Sets.newLinkedHashSet(modules.rowKeySet());
}
@Override
public Collection<Module> getModuleVersions(Name id) {
return Collections.unmodifiableCollection(modules.row(id).values());
}
@Override
public Module getLatestModuleVersion(Name id) {
return latestModules.get(id);
}
@Override
public Module getLatestModuleVersion(Name id, Version minVersion, Version maxVersion) {
Module module = latestModules.get(id);
if (module != null) {
if (module.getVersion().compareTo(maxVersion) < 0 && module.getVersion().compareTo(minVersion) >= 0) {
return module;
}
if (module.getVersion().compareTo(minVersion) >= 0) {
Module result = null;
for (Map.Entry<Version, Module> item : modules.row(id).entrySet()) {
if (item.getKey().compareTo(minVersion) >= 0 && item.getKey().compareTo(maxVersion) < 0
&& (result == null || item.getKey().compareTo(result.getVersion()) > 0)) {
result = item.getValue();
}
}
return result;
}
}
return null;
}
@Override
public Module getModule(Name moduleId, Version version) {
return modules.get(moduleId, version);
}
@Override
public int size() {
return modules.size();
}
@Override
public boolean isEmpty() {
return modules.isEmpty();
}
@Override
public boolean contains(Object o) {
if (o instanceof Module) {
Module module = (Module) o;
return modules.contains(module.getId(), module.getVersion());
}
return false;
}
@Override
public Iterator<Module> iterator() {
Iterator<Module> it = modules.values().iterator();
return new Iterator<Module>() {
private Module current;
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public Module next() {
current = it.next();
return current;
}
@Override
public void remove() {
it.remove();
Module latest = latestModules.get(current.getId());
if (latest.getVersion().compareTo(current.getVersion()) == 0) {
updateLatestFor(current.getId());
}
}
};
}
@Override
public Object[] toArray() {
return modules.values().toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return modules.values().toArray(a);
}
@Override
public boolean containsAll(Collection<?> c) {
for (Object o : c) {
if (!contains(o)) {
return false;
}
}
return true;
}
@Override
public void clear() {
modules.clear();
latestModules.clear();
}
}