package org.jtheque.file.impl;
/*
* Copyright JTheque (Baptiste Wicht)
*
* 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.
*/
import org.jtheque.file.Exporter;
import org.jtheque.file.FileService;
import org.jtheque.file.Importer;
import org.jtheque.file.ModuleBackup;
import org.jtheque.file.ModuleBackuper;
import org.jtheque.modules.Module;
import org.jtheque.modules.ModuleListener;
import org.jtheque.modules.ModuleResourceCache;
import org.jtheque.utils.StringUtils;
import org.jtheque.utils.annotations.GuardedBy;
import org.jtheque.utils.annotations.GuardedInternally;
import org.jtheque.utils.annotations.ThreadSafe;
import org.jtheque.utils.collections.ArrayUtils;
import org.jtheque.utils.collections.CollectionUtils;
import org.jtheque.utils.io.FileException;
import org.jtheque.xml.utils.XMLException;
import java.io.File;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* A FileService implementation.
*
* @author Baptiste Wicht
*/
@ThreadSafe
public final class FileServiceImpl implements FileService, ModuleListener {
@GuardedInternally
private final List<ModuleBackuper> backupers = CollectionUtils.newConcurrentList();
@GuardedBy("exporters")
private final Map<String, Set<Exporter<?>>> exporters = CollectionUtils.newHashMap(3);
@GuardedBy("importers")
private final Map<String, Set<Importer>> importers = CollectionUtils.newHashMap(3);
@Override
public void registerExporter(String module, Exporter<?> exporter){
synchronized (exporters){
if(!exporters.containsKey(module)){
exporters.put(module, CollectionUtils.<Exporter<?>>newSet());
}
exporters.get(module).add(exporter);
}
}
@Override
public void registerImporter(String module, Importer importer) {
synchronized (importers) {
if (!importers.containsKey(module)) {
importers.put(module, CollectionUtils.<Importer>newSet());
}
importers.get(module).add(importer);
}
}
@Override
public <T> void exportDatas(String module, String fileType, String file, Collection<T> datas) throws FileException {
synchronized (exporters) {
if (exporters.containsKey(module)) {
for (Exporter<?> exporter : exporters.get(module)) {
if (exporter.canExportTo(fileType)) {
((Exporter<T>) exporter).export(file, datas);
return;
}
}
}
}
}
@Override
public void importDatas(String module, String fileType, String file) throws FileException {
synchronized (importers) {
if (importers.containsKey(module)) {
for (Importer importer : importers.get(module)) {
if (importer.canImportFrom(fileType)) {
importer.importFrom(file);
return;
}
}
}
}
}
@Override
public void backup(File file) {
List<ModuleBackuper> activeBackupers = CollectionUtils.copyOf(backupers);
Collections.sort(activeBackupers, new ModuleBackupComparator());
Collection<ModuleBackup> backups = CollectionUtils.newList(activeBackupers.size());
for (ModuleBackuper backuper : activeBackupers) {
backups.add(backuper.backup());
}
XMLBackuper.backup(file, backups);
}
@Override
public void restore(File file) throws XMLException {
List<ModuleBackuper> activeBackupers = CollectionUtils.copyOf(backupers);
Collections.sort(activeBackupers, new ModuleBackupComparator());
List<ModuleBackup> restores = XMLRestorer.restore(file);
for (ModuleBackuper backuper : activeBackupers) {
for (ModuleBackup backup : restores) {
if (backup.getId().equals(backuper.getId())) {
backuper.restore(backup);
break;
}
}
}
}
@Override
public void registerBackuper(String moduleId, ModuleBackuper backuper) {
backupers.add(backuper);
if (StringUtils.isNotEmpty(moduleId)) {
ModuleResourceCache.addResource(moduleId, ModuleBackuper.class, backuper);
}
}
@Override
public void moduleStopped(Module module) {
Set<ModuleBackuper> resources = ModuleResourceCache.getResources(module.getId(), ModuleBackuper.class);
for (ModuleBackuper backuper : resources) {
backupers.remove(backuper);
}
ModuleResourceCache.removeResourceOfType(module.getId(), ModuleBackuper.class);
}
@Override
public void moduleStarted(Module module) {
//Nothing to do here
}
@Override
public void moduleInstalled(Module module) {
//Nothing to do here
}
@Override
public void moduleUninstalled(Module module) {
//Nothing to do here
}
/**
* A module backup comparator to compare the module backups using their dependencies.
*
* @author Baptiste Wicht
*/
private static final class ModuleBackupComparator implements Comparator<ModuleBackuper>, Serializable {
private static final long serialVersionUID = -6570472886580751916L;
@Override
public int compare(ModuleBackuper backup1, ModuleBackuper backup2) {
boolean hasDependency = StringUtils.isNotEmpty(backup1.getDependencies());
boolean hasOtherDependency = StringUtils.isNotEmpty(backup2.getDependencies());
if (hasDependency && !hasOtherDependency) {
return 1;
} else if (!hasDependency && hasOtherDependency) {
return -1;
} else {
//The other depends on me
if (ArrayUtils.contains(backup2.getDependencies(), backup1.getId())) {
return -1;
}
//I depends on the other
if (ArrayUtils.contains(backup1.getDependencies(), backup2.getId())) {
return 1;
}
}
return 0;
}
}
}