/**
* Copyright (C) 2001-2017 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.com
*
* This program 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, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.repository;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import com.rapidminer.RapidMiner;
import com.rapidminer.io.process.XMLTools;
import com.rapidminer.repository.local.LocalRepository;
import com.rapidminer.tools.FileSystemService;
import com.rapidminer.tools.LogService;
import com.rapidminer.tools.XMLException;
/**
* This {@link RepositoryProvider} will use the {@value #FILE_NAME} to {@link #load()} and
* {@link #save()} the repository configuration.
*
* @author Marcel Michel
*
*/
public class FileRepositoryProvider implements RepositoryProvider {
private static final Logger LOGGER = LogService.getRoot();
public static final String TAG_LOCAL_REPOSITORY = "localRepository";
public static final String TAG_REPOSITORIES = "repositories";
public static final String FILE_NAME = "repositories.xml";
private final List<Element> failedToLoad = new LinkedList<>();
private File getConfigFile() {
return FileSystemService.getUserConfigFile(FILE_NAME);
}
@Override
public List<Repository> load() {
// clear failed list first
failedToLoad.clear();
List<Repository> result = new LinkedList<>();
if (!RapidMiner.getExecutionMode().canAccessFilesystem()) {
LOGGER.info("Cannot access file system in execution mode " + RapidMiner.getExecutionMode()
+ ". Not loading repositories.");
return result;
}
File file = getConfigFile();
if (file.exists()) {
LOGGER.config("Loading repositories from " + file);
try {
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(file);
if (!doc.getDocumentElement().getTagName().equals(TAG_REPOSITORIES)) {
LOGGER.warning("Broken repositories file. Root element must be <reposities>.");
return result;
}
NodeList list = doc.getDocumentElement().getChildNodes();
for (int i = 0; i < list.getLength(); i++) {
if (list.item(i) instanceof Element) {
Element element = (Element) list.item(i);
String tagName = element.getTagName();
if (TAG_LOCAL_REPOSITORY.equals(tagName)) {
try {
result.add(LocalRepository.fromXML(element));
} catch (RepositoryException | XMLException e) {
failedToLoad.add(element);
LOGGER.log(Level.WARNING, "Cannot read local repository entry.", e);
}
} else {
boolean foundFactory = false;
for (CustomRepositoryFactory factory : CustomRepositoryRegistry.INSTANCE.getFactories()) {
if (tagName.equals(factory.getXMLTag())) {
try {
result.add(factory.fromXML(element));
} catch (RepositoryException | XMLException e) {
failedToLoad.add(element);
LOGGER.log(Level.WARNING, "Cannot read custom repository entry.", e);
}
foundFactory = true;
break;
}
}
if (!foundFactory) {
LOGGER.warning("Unknown tag: " + tagName);
failedToLoad.add(element);
}
}
}
}
} catch (RuntimeException | SAXException | IOException | ParserConfigurationException e) {
LOGGER.log(Level.WARNING, "Cannot read repository configuration file '" + file + "': " + e, e);
}
}
return result;
}
@Override
public void save(List<Repository> repositories) {
if (!RapidMiner.getExecutionMode().canAccessFilesystem()) {
LOGGER.config("Cannot access file system in execution mode " + RapidMiner.getExecutionMode()
+ ". Not saving repositories.");
return;
}
Document doc;
try {
doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
} catch (ParserConfigurationException e) {
LOGGER.log(Level.WARNING, "Cannot save repositories: " + e, e);
return;
}
Element root = doc.createElement(TAG_REPOSITORIES);
doc.appendChild(root);
for (Repository repository : repositories) {
if (repository.shouldSave()) {
Element repositoryElement = repository.createXML(doc);
if (repositoryElement != null) {
root.appendChild(repositoryElement);
}
}
}
// Store failed element when saving repositories so they are not lost once an external error
// (e.g. no write access) has been fixed
for (Element failedElem : failedToLoad) {
root.appendChild(doc.importNode(failedElem, true));
}
try {
XMLTools.stream(doc, getConfigFile(), null);
} catch (XMLException e) {
LOGGER.log(Level.WARNING, "Cannot save repositories: " + e, e);
}
}
}