/**
*
* Copyright (c) 2009-2016 Freedomotic team http://freedomotic.com
*
* This file is part of Freedomotic
*
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, 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 General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* Freedomotic; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
package com.freedomotic.reactions;
import com.freedomotic.app.Freedomotic;
import com.freedomotic.exceptions.DataUpgradeException;
import com.freedomotic.exceptions.RepositoryException;
import com.freedomotic.persistence.DataUpgradeService;
import com.freedomotic.persistence.FreedomXStream;
import com.freedomotic.persistence.XmlPreprocessor;
import com.freedomotic.settings.Info;
import com.google.inject.Inject;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.XStreamException;
import com.thoughtworks.xstream.mapper.CannotResolveClassException;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.freedomotic.util.FileOperations.writeSummaryFile;
/**
*
* @author Enrico Nicoletti
*/
class CommandRepositoryImpl implements CommandRepository {
private static final Logger LOG = LoggerFactory.getLogger(CommandRepositoryImpl.class.getName());
private static final Map<String, Command> userCommands = new HashMap<>();
private static final Map<String, Command> hardwareCommands = new HashMap<>();
private static final String COMMAND_FILE_EXTENSION = ".xcmd";
private final DataUpgradeService dataUpgradeService;
@Inject
public CommandRepositoryImpl(DataUpgradeService dataUpgradeService) {
this.dataUpgradeService = dataUpgradeService;
}
/**
* @deprecated
*
* @param c
*/
@Deprecated
public static void add(Command c) {
if (c != null) {
if (!c.isHardwareLevel()) {
if (!userCommands.containsKey(c.getName().trim().toLowerCase())) {
userCommands.put(c.getName(),
c);
LOG.trace("Added command \"{}\" to the list of user commands", c.getName());
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Command \"{}\" already in the list of user commands. Skipped", c.getName());
}
}
} else if (!hardwareCommands.containsKey(c.getName().trim().toLowerCase())) {
hardwareCommands.put(c.getName(),
c);
LOG.trace("Added command \"{}\" to the list of hardware commands", c.getName());
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Command \"{}\" already in the list of hardware commands. Skipped", c.getName());
}
}
} else {
LOG.warn("Attempt to add a null user command to the list. Skipped");
}
}
/**
* @deprecated
*
* @param input
*/
@Deprecated
public static void remove(Command input) {
if (input.isHardwareLevel()) {
hardwareCommands.remove(input.getName());
} else {
userCommands.remove(input.getName());
}
}
/**
*
* @return
*/
public static int size() {
return userCommands.size();
}
/**
* @deprecated
*
* @return
*/
@Deprecated
public static Iterator<Command> iterator() {
return userCommands.values().iterator();
}
/**
* @deprecated
*
* @param name
* @return
*/
@Deprecated
public static Command getCommand(String name) {
Command command = userCommands.get(name.trim());
if (command != null) {
return command;
}
Command hwCommand = getHardwareCommand(name);
return hwCommand;
}
/**
* @deprecated
*
* @param uuid
* @return
*/
@Deprecated
public static Command getCommandByUUID(String uuid) {
for (Command c : userCommands.values()) {
if (c.getUuid().equalsIgnoreCase(uuid)) {
return c;
}
}
for (Command c : hardwareCommands.values()) {
if (c.getUuid().equalsIgnoreCase(uuid)) {
return c;
}
}
return null;
}
/**
*
* @return
*/
@Override
public List<Command> findHardwareCommands() {
return new ArrayList(hardwareCommands.values());
}
/**
*
* @return
*/
@Override
public List<Command> findUserCommands() {
return new ArrayList(userCommands.values());
}
/**
* @deprecated
*
* @param name
* @return
*/
@Deprecated
public static Command getHardwareCommand(String name) {
Command command = hardwareCommands.get(name.trim());
if (command == null) {
LOG.error("Missing command \"{}\"" + "''. "
+ "Maybe the related plugin is not installed or cannot be loaded", name);
}
return command;
}
/**
*
* @param folder
*/
@Override
public void loadCommands(File folder) {
XStream xstream = FreedomXStream.getXstream();
File[] files = folder.listFiles();
// This filter only returns object files
FileFilter objectFileFileter
= new FileFilter() {
public boolean accept(File file) {
if (file.isFile() && file.getName().endsWith(COMMAND_FILE_EXTENSION)) {
return true;
} else {
return false;
}
}
};
files = folder.listFiles(objectFileFileter);
if (files != null) {
try {
for (File file : files) {
Command command;
String xml;
try {
xml = XmlPreprocessor.validate(file, Info.PATHS.PATH_CONFIG_FOLDER + "/validator/command.dtd");
} catch (IOException ex) {
LOG.error(Freedomotic.getStackTraceInfo(ex));
continue;
}
try {
Properties dataProperties = new Properties();
String fromVersion;
try {
dataProperties.load(new FileInputStream(new File(Info.PATHS.PATH_DATA_FOLDER + "/data.properties")));
fromVersion = dataProperties.getProperty("data.version");
} catch (IOException iOException) {
LOG.error(Freedomotic.getStackTraceInfo(iOException));
// Fallback to a default version for older version without that properties file
fromVersion = "5.5.0";
}
xml = (String) dataUpgradeService.upgrade(Command.class, xml, fromVersion);
command = (Command) xstream.fromXML(xml);
} catch (DataUpgradeException dataUpgradeException) {
throw new RepositoryException("Cannot upgrade Command file " + file.getAbsolutePath(), dataUpgradeException);
} catch (XStreamException e) {
throw new RepositoryException("XML parsing error. Readed XML is \n" + xml, e);
}
try {
if (command.isHardwareLevel()) { //an hardware level command
hardwareCommands.put(command.getName(),
command);
} else { //a user level commmand
if (folder.getAbsolutePath().startsWith(Info.PATHS.PATH_PLUGINS_FOLDER.getAbsolutePath())) {
command.setEditable(false);
}
add(command);
}
} catch (CannotResolveClassException e) {
LOG.error("Cannot unserialize command due to unrecognized class \"{}\" in \n{}", new Object[]{e.getMessage(), xml});
}
}
} catch (Exception ex) {
LOG.error("Error while loading command", Freedomotic.getStackTraceInfo(ex));
}
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("No commands to load from this folder \"{}\"", folder.toString());
}
}
}
/**
*
* @param folder
*/
@Override
public void saveCommands(File folder) {
if (userCommands.isEmpty()) {
LOG.warn("There are no commands to persist, \"{}\" will not be altered.", folder.getAbsolutePath());
return;
}
if (!folder.isDirectory()) {
LOG.warn("\"{}\" is not a valid command folder. Skipped", folder.getAbsoluteFile());
return;
}
deleteCommandFiles(folder);
try {
LOG.info("Saving commands to file into \"{}\"", folder.getAbsolutePath());
StringBuilder summaryContent = new StringBuilder();
for (Command c : userCommands.values()) {
if (c.isEditable()) {
String uuid = c.getUuid();
if ((uuid == null) || uuid.isEmpty()) {
c.setUUID(UUID.randomUUID().toString());
}
String fileName = c.getUuid() + COMMAND_FILE_EXTENSION;
File file = new File(folder + "/" + fileName);
FreedomXStream.toXML(c, file);
summaryContent.append(fileName).append("\t\t").append(c.getName())
.append("\t\t\t").append(c.getReceiver()).append("\n");
}
}
writeSummaryFile(new File(folder, "index.txt"), "#Filename \t\t #CommandName \t\t\t #Destination\n", summaryContent.toString());
} catch (Exception e) {
LOG.error("Error while saving commands to \"" + folder.getAbsolutePath() + "\"", e);
}
}
/**
*
* @param folder
*/
private static void deleteCommandFiles(File folder) {
File[] files = folder.listFiles();
// This filter only returns object files
FileFilter objectFileFileter
= new FileFilter() {
public boolean accept(File file) {
if (file.isFile() && file.getName().endsWith(COMMAND_FILE_EXTENSION)) {
return true;
} else {
return false;
}
}
};
files = folder.listFiles(objectFileFileter);
for (File file : files) {
file.delete();
}
}
@Override
public List<Command> findAll() {
List<Command> cl = new ArrayList<>(userCommands.values());
cl.addAll(hardwareCommands.values());
return cl;
}
@Override
public List<Command> findByName(String name) {
List<Command> cl = new ArrayList<>();
for (Command c : findAll()) {
if (c.getName().equalsIgnoreCase(name)) {
cl.add(c);
}
}
return cl;
}
@Override
public Command findOne(String uuid) {
return getCommandByUUID(uuid);
}
@Override
public boolean create(Command item) {
try {
add(item);
return true;
} catch (Exception e) {
LOG.error(Freedomotic.getStackTraceInfo(e));
return false;
}
}
@Override
public boolean delete(Command item) {
try {
remove(item);
return true;
} catch (Exception e) {
LOG.error(Freedomotic.getStackTraceInfo(e));
return false;
}
}
@Override
public boolean delete(String uuid) {
return delete(findOne(uuid));
}
@Override
public Command modify(String uuid, Command data) {
try {
delete(uuid);
data.setUUID(uuid);
add(data);
return data;
} catch (Exception e) {
LOG.error(Freedomotic.getStackTraceInfo(e));
return null;
}
}
@Override
public Command copy(Command command) {
try {
Command c = findOne(command.getUuid()).clone();
c.setName("Copy of " + c.getName());
add(c);
return c;
} catch (Exception e) {
LOG.error(Freedomotic.getStackTraceInfo(e));
return null;
}
}
@Override
public void deleteAll() {
try {
for (Command c : findAll()) {
delete(c);
}
} catch (Exception e) {
LOG.error(Freedomotic.getStackTraceInfo(e));
} finally {
hardwareCommands.clear();
userCommands.clear();
}
}
}