/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <hr>
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* This file has been modified by the OpenOLAT community. Changes are licensed
* under the Apache 2.0 license as the original file.
*/
package org.olat.repository;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.olat.core.CoreSpringFactory;
import org.olat.core.gui.media.MediaResource;
import org.olat.core.logging.OLATRuntimeException;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.FileUtils;
import org.olat.core.util.StringHelper;
import org.olat.core.util.io.HttpServletResponseOutputStream;
import org.olat.core.util.io.ShieldOutputStream;
import org.olat.core.util.vfs.LocalFileImpl;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.vfs.VFSManager;
import org.olat.core.util.xml.XStreamHelper;
import org.olat.repository.handlers.RepositoryHandler;
import org.olat.repository.handlers.RepositoryHandlerFactory;
import com.thoughtworks.xstream.XStream;
/**
* Initial Date: 19.05.2005
*
* @author Mike Stock
*
* Comment:
*
*/
public class RepositoryEntryImportExport {
private static final OLog log = Tracing.createLoggerFor(RepositoryEntryImportExport.class);
private static final String CONTENT_FILE = "repo.zip";
public static final String PROPERTIES_FILE = "repo.xml";
private static final String PROP_ROOT = "RepositoryEntryProperties";
private static final String PROP_SOFTKEY = "Softkey";
private static final String PROP_RESOURCENAME = "ResourceName";
private static final String PROP_DISPLAYNAME = "DisplayName";
private static final String PROP_DECRIPTION = "Description";
private static final String PROP_INITIALAUTHOR = "InitialAuthor";
private boolean propertiesLoaded = false;
private RepositoryEntry re;
private File baseDirectory;
private RepositoryEntryImport repositoryProperties;
/**
* Create a RepositoryEntryImportExport instance to do an export.
*
* @param re
* @param baseDirecotry
*/
public RepositoryEntryImportExport(RepositoryEntry re, File baseDirecotry) {
this.re = re;
this.baseDirectory = baseDirecotry;
}
/**
* Create a RepositoryEntryImportExport instance to do an import.
*
* @param baseDirecotry
*/
public RepositoryEntryImportExport(File baseDirectory) {
this.baseDirectory = baseDirectory;
}
public RepositoryEntryImportExport(File baseDirectory, String subDir) {
this.baseDirectory = new File(baseDirectory, subDir);
}
public boolean anyExportedPropertiesAvailable() {
return new File(baseDirectory, PROPERTIES_FILE).exists();
}
/**
* Export repository entry (contents and metadata.
*
* @return True upon success, false otherwise.
*/
public boolean exportDoExport() {
exportDoExportProperties();
return exportDoExportContent();
}
/**
* Export metadata of a repository entry to a file.
* Only one repository entry's metadata may be exported into a directory. The
* file name of the properties file will be the same for all repository entries!
*/
public void exportDoExportProperties() {
// save repository entry properties
FileOutputStream fOut = null;
try {
fOut = new FileOutputStream(new File(baseDirectory, PROPERTIES_FILE));
XStream xstream = getXStream();
RepositoryEntryImport imp = new RepositoryEntryImport(re);
RepositoryManager rm = RepositoryManager.getInstance();
VFSLeaf image = rm.getImage(re);
if(image instanceof LocalFileImpl) {
imp.setImageName(image.getName());
FileUtils.copyFileToDir(((LocalFileImpl)image).getBasefile(), baseDirectory, "");
}
RepositoryService repositoryService = CoreSpringFactory.getImpl(RepositoryService.class);
VFSLeaf movie = repositoryService.getIntroductionMovie(re);
if(movie instanceof LocalFileImpl) {
imp.setMovieName(movie.getName());
FileUtils.copyFileToDir(((LocalFileImpl)movie).getBasefile(), baseDirectory, "");
}
xstream.toXML(imp, fOut);
} catch (IOException ioe) {
throw new OLATRuntimeException("Error writing repo properties.", ioe);
} finally {
FileUtils.closeSafely(fOut);
}
}
public void exportDoExportProperties(ZipOutputStream zout) throws IOException {
RepositoryEntryImport imp = new RepositoryEntryImport(re);
RepositoryManager rm = RepositoryManager.getInstance();
VFSLeaf image = rm.getImage(re);
if(image != null) {
imp.setImageName(image.getName());
zout.putNextEntry(new ZipEntry(image.getName()));
try(InputStream inImage=image.getInputStream()) {
FileUtils.copy(inImage, new ShieldOutputStream(zout));
} catch(Exception e) {
log.error("", e);
}
zout.closeEntry();
}
RepositoryService repositoryService = CoreSpringFactory.getImpl(RepositoryService.class);
VFSLeaf movie = repositoryService.getIntroductionMovie(re);
if(movie != null) {
imp.setMovieName(movie.getName());
zout.putNextEntry(new ZipEntry(movie.getName()));
try(InputStream inMovie=movie.getInputStream()) {
FileUtils.copy(inMovie, new ShieldOutputStream(zout));
} catch(Exception e) {
log.error("", e);
}
zout.closeEntry();
}
zout.putNextEntry(new ZipEntry(PROPERTIES_FILE));
getXStream().toXML(imp, new ShieldOutputStream(zout));
zout.closeEntry();
}
/**
* Export a repository entry referenced by a course node to the given export directory.
* User importReferencedRepositoryEntry to import again.
* @return True upon success, false otherwise.
*
*/
public boolean exportDoExportContent() {
// export resource
RepositoryHandler rh = RepositoryHandlerFactory.getInstance().getRepositoryHandler(re);
MediaResource mr = rh.getAsMediaResource(re.getOlatResource(), false);
FileOutputStream fOut = null;
try {
fOut = new FileOutputStream(new File(baseDirectory, CONTENT_FILE));
InputStream in = mr.getInputStream();
if(in == null) {
HttpServletResponse hres = new HttpServletResponseOutputStream(fOut);
mr.prepare(hres);
} else {
IOUtils.copy(mr.getInputStream(), fOut);
}
fOut.flush();
} catch (IOException fnfe) {
return false;
} finally {
IOUtils.closeQuietly(fOut);
mr.release();
}
return true;
}
public RepositoryEntry importContent(RepositoryEntry newEntry, VFSContainer mediaContainer) {
if(!anyExportedPropertiesAvailable()) return newEntry;
RepositoryManager repositoryManager = CoreSpringFactory.getImpl(RepositoryManager.class);
if(StringHelper.containsNonWhitespace(getImageName())) {
File newFile = new File(baseDirectory, getImageName());
VFSLeaf newImage = new LocalFileImpl(newFile);
repositoryManager.setImage(newImage, newEntry);
}
if(StringHelper.containsNonWhitespace(getMovieName())) {
String movieName = getMovieName();
String extension = FileUtils.getFileSuffix(movieName);
File newFile = new File(baseDirectory, movieName);
try(InputStream inStream = new FileInputStream(newFile)) {
VFSLeaf movieLeaf = mediaContainer.createChildLeaf(newEntry.getKey() + "." + extension);
VFSManager.copyContent(inStream, movieLeaf);
} catch(IOException e) {
log.error("", e);
}
}
return setRepoEntryPropertiesFromImport(newEntry);
}
/**
* Update the repo entry property from the current import information in the database
*
* @param newEntry
* @return
*/
public RepositoryEntry setRepoEntryPropertiesFromImport(RepositoryEntry newEntry) {
if(!propertiesLoaded) {
loadConfiguration();
}
RepositoryManager repositoryManager = CoreSpringFactory.getImpl(RepositoryManager.class);
return repositoryManager.setDescriptionAndName(newEntry, newEntry.getDisplayname(), null,
repositoryProperties.getAuthors(), repositoryProperties.getDescription(),
repositoryProperties.getObjectives(), repositoryProperties.getRequirements(),
repositoryProperties.getCredits(), repositoryProperties.getMainLanguage(),
repositoryProperties.getLocation(), repositoryProperties.getExpenditureOfWork(), null);
}
/**
* Returns the exported repository file.
*
* @return exported repository file
*/
public File importGetExportedFile() {
return new File(baseDirectory, CONTENT_FILE);
}
/**
* Read previousely exported Propertiesproperties
*/
private void loadConfiguration() {
try {
if(baseDirectory.exists()) {
if(baseDirectory.getName().endsWith(".zip")) {
Path fPath = FileSystems.newFileSystem(baseDirectory.toPath(), null).getPath("/");
Path manifestPath = fPath.resolve("export").resolve(PROPERTIES_FILE);
try(InputStream inputFile = Files.newInputStream(manifestPath, StandardOpenOption.READ)) {
XStream xstream = getXStream();
repositoryProperties = (RepositoryEntryImport)xstream.fromXML(inputFile);
} catch(Exception e) {
log.error("Cannot read repo.xml im zip", e);
}
} else {
File inputFile = new File(baseDirectory, PROPERTIES_FILE);
if(inputFile.exists()) {
XStream xstream = getXStream();
repositoryProperties = (RepositoryEntryImport)xstream.fromXML(inputFile);
} else {
repositoryProperties = new RepositoryEntryImport();
}
}
} else {
repositoryProperties = new RepositoryEntryImport();
}
propertiesLoaded = true;
} catch (Exception ce) {
throw new OLATRuntimeException("Error importing repository entry properties.", ce);
}
}
/**
* Get the repo entry import metadata from the given path. E.g. usefull
* when reading from an unzipped archive.
*
* @param repoXmlPath
* @return The RepositoryEntryImport or NULL
*/
public static RepositoryEntryImport getConfiguration(Path repoXmlPath) {
try (InputStream in=Files.newInputStream(repoXmlPath)) {
XStream xstream = getXStream();
return (RepositoryEntryImport)xstream.fromXML(in);
} catch(IOException e) {
log.error("", e);
return null;
}
}
/**
* Get the repo entry import metadata from the given stream. E.g. usefull
* when reading from an ZIP file without inflating it.
*
* @param repoMetaFileInputStream
* @return The RepositoryEntryImport or NULL
*/
public static RepositoryEntryImport getConfiguration(InputStream repoMetaFileInputStream) {
XStream xstream = getXStream();
return (RepositoryEntryImport)xstream.fromXML(repoMetaFileInputStream);
}
/**
* Helper to load the xstream instances with all the aliases for the
* RepositoryEntryImport class
*
* @return
*/
private static XStream getXStream() {
XStream xStream = XStreamHelper.createXStreamInstance();
xStream.alias(PROP_ROOT, RepositoryEntryImport.class);
xStream.aliasField(PROP_SOFTKEY, RepositoryEntryImport.class, "softkey");
xStream.aliasField(PROP_RESOURCENAME, RepositoryEntryImport.class, "resourcename");
xStream.aliasField(PROP_DISPLAYNAME, RepositoryEntryImport.class, "displayname");
xStream.aliasField(PROP_DECRIPTION, RepositoryEntryImport.class, "description");
xStream.aliasField(PROP_INITIALAUTHOR, RepositoryEntryImport.class, "initialAuthor");
xStream.omitField(RepositoryEntryImport.class, "outer-class");
xStream.ignoreUnknownElements();
return xStream;
}
/**
* @return The softkey
*/
public String getSoftkey() {
if(!propertiesLoaded) {
loadConfiguration();
}
return repositoryProperties.getSoftkey();
}
/**
* @return The display name
*/
public String getDisplayName() {
if(!propertiesLoaded) {
loadConfiguration();
}
return repositoryProperties.getDisplayname();
}
/**
* @return the resource name
*/
public String getResourceName() {
if(!propertiesLoaded) {
loadConfiguration();
}
return repositoryProperties.getResourcename();
}
/**
* @return the descritpion
*/
public String getDescription() {
if(!propertiesLoaded) {
loadConfiguration();
}
return repositoryProperties.getDescription();
}
/**
* @return the initial author
*/
public String getInitialAuthor() {
if(!propertiesLoaded) {
loadConfiguration();
}
return repositoryProperties.getInitialAuthor();
}
public String getMovieName() {
if(!propertiesLoaded) {
loadConfiguration();
}
return repositoryProperties.getMovieName();
}
public String getImageName() {
if(!propertiesLoaded) {
loadConfiguration();
}
return repositoryProperties.getImageName();
}
public class RepositoryEntryImport {
private Long key;
private String softkey;
private String resourcename;
private String displayname;
private String description;
private String initialAuthor;
private String authors;
private String mainLanguage;
private String objectives;
private String requirements;
private String credits;
private String expenditureOfWork;
private String location;
private String movieName;
private String imageName;
public RepositoryEntryImport() {
//
}
public RepositoryEntryImport(RepositoryEntry re) {
key = re.getKey();
softkey = re.getSoftkey();
resourcename = re.getResourcename();
displayname = re.getDisplayname();
description = re.getDescription();
initialAuthor = re.getInitialAuthor();
authors = re.getAuthors();
mainLanguage = re.getMainLanguage();
objectives = re.getObjectives();
requirements = re.getRequirements();
credits = re.getCredits();
expenditureOfWork = re.getExpenditureOfWork();
}
public Long getKey() {
return key;
}
public void setKey(Long key) {
this.key = key;
}
public String getMovieName() {
return movieName;
}
public void setMovieName(String movieName) {
this.movieName = movieName;
}
public String getImageName() {
return imageName;
}
public void setImageName(String imageName) {
this.imageName = imageName;
}
public String getSoftkey() {
return softkey;
}
public void setSoftkey(String softkey) {
this.softkey = softkey;
}
public String getResourcename() {
return resourcename;
}
public void setResourcename(String resourcename) {
this.resourcename = resourcename;
}
public String getDisplayname() {
return displayname;
}
public void setDisplayname(String displayname) {
this.displayname = displayname;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getInitialAuthor() {
return initialAuthor;
}
public void setInitialAuthor(String initialAuthor) {
this.initialAuthor = initialAuthor;
}
public String getAuthors() {
return authors;
}
public void setAuthors(String authors) {
this.authors = authors;
}
public String getMainLanguage() {
return mainLanguage;
}
public void setMainLanguage(String mainLanguage) {
this.mainLanguage = mainLanguage;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getObjectives() {
return objectives;
}
public void setObjectives(String objectives) {
this.objectives = objectives;
}
public String getRequirements() {
return requirements;
}
public void setRequirements(String requirements) {
this.requirements = requirements;
}
public String getCredits() {
return credits;
}
public void setCredits(String credits) {
this.credits = credits;
}
public String getExpenditureOfWork() {
return expenditureOfWork;
}
public void setExpenditureOfWork(String expenditureOfWork) {
this.expenditureOfWork = expenditureOfWork;
}
}
}