/*
* 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.Charsets;
import com.google.common.base.Preconditions;
import com.google.gson.JsonParseException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* Helper class for loading modules from a file location (directory or archive file).
*
* @author Immortius
*/
public class ModuleLoader {
private Path moduleInfoPath = Paths.get("module.info");
private Path directoryCodeLocation = Paths.get("build", "classes");
private final ModuleMetadataJsonAdapter metadataReader;
public ModuleLoader() {
metadataReader = new ModuleMetadataJsonAdapter();
}
/**
* @param metadataReader The metadata reader to use when loading module metadata.
*/
public ModuleLoader(ModuleMetadataJsonAdapter metadataReader) {
this.metadataReader = metadataReader;
}
/**
* @return The location within a module where the metadata can be found
*/
public Path getModuleInfoPath() {
return moduleInfoPath;
}
/**
* @param moduleInfoFilename The location within a module where the metadata can be found
*/
public void setModuleInfoPath(Path moduleInfoFilename) {
this.moduleInfoPath = moduleInfoFilename;
}
/**
* @return The location in a directory module where code can be found
*/
public Path getDirectoryCodeLocation() {
return directoryCodeLocation;
}
/**
* @param directoryCodeLocation The location in a directory module where code can be found
*/
public void setDirectoryCodeLocation(Path directoryCodeLocation) {
this.directoryCodeLocation = directoryCodeLocation;
}
/**
* @param modulePath The path to the module to load
* @return The loaded module, or null if the path is not a module (contains no module metadata)
* @throws IOException If an error occurs loading the module
*/
public Module load(Path modulePath) throws IOException {
Preconditions.checkArgument(Files.exists(modulePath), "Module does not exist at: " + modulePath);
if (Files.isDirectory(modulePath)) {
return loadDirectoryModule(modulePath);
} else if (Files.isRegularFile(modulePath)) {
return loadArchiveModule(modulePath);
}
return null;
}
private Module loadArchiveModule(Path modulePath) throws IOException {
try (ZipFile zipFile = new ZipFile(modulePath.toFile())) {
ZipEntry modInfoEntry = zipFile.getEntry(moduleInfoPath.toString());
if (modInfoEntry != null) {
try (Reader reader = new InputStreamReader(zipFile.getInputStream(modInfoEntry), Charsets.UTF_8)) {
try {
ModuleMetadata metadata = metadataReader.read(reader);
return new ArchiveModule(modulePath, metadata);
} catch (JsonParseException e) {
throw new IOException("Failed to read metadata for module " + modulePath, e);
}
}
}
}
return null;
}
private Module loadDirectoryModule(Path modulePath) throws IOException {
Path modInfoFile = modulePath.resolve(moduleInfoPath);
if (Files.isRegularFile(modInfoFile)) {
try (Reader reader = Files.newBufferedReader(modInfoFile, Charsets.UTF_8)) {
return new PathModule(modulePath, modulePath.resolve(directoryCodeLocation), metadataReader.read(reader));
}
}
return null;
}
}