/* ==================================================================
* BackupController.java - 2/11/2016 8:39:46 AM
*
* Copyright 2007-2016 SolarNetwork.net Dev Team
*
* 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 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
* ==================================================================
*/
package net.solarnetwork.node.setup.web;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import net.solarnetwork.node.backup.Backup;
import net.solarnetwork.node.backup.BackupInfo;
import net.solarnetwork.node.backup.BackupManager;
import net.solarnetwork.node.backup.BackupService;
import net.solarnetwork.util.OptionalService;
import net.solarnetwork.web.domain.Response;
/**
* Controller for backup support.
*
* @author matt
* @version 1.0
*/
@Controller
@RequestMapping("/a/backups")
public class BackupController extends BaseSetupController {
private Future<Backup> importTask;
@Resource(name = "backupManager")
private OptionalService<BackupManager> backupManagerTracker;
@Autowired
private MessageSource messageSource;
/**
* Get a list of all available backups from the active backup service.
*
* @return All avaialble backups.
*/
@RequestMapping(value = { "", "/" }, method = RequestMethod.GET)
@ResponseBody
public Response<List<Backup>> availableBackups() {
final BackupManager backupManager = backupManagerTracker.service();
List<Backup> backups = new ArrayList<Backup>();
if ( backupManager != null ) {
BackupService service = backupManager.activeBackupService();
if ( service != null ) {
backups.addAll(service.getAvailableBackups());
Collections.sort(backups, new Comparator<Backup>() {
@Override
public int compare(Backup o1, Backup o2) {
// sort in reverse chronological order (newest to oldest)
return o2.getDate().compareTo(o1.getDate());
}
});
}
}
return Response.response(backups);
}
/**
* Create a new backup.
*
* @param model
* @return
*/
@RequestMapping(value = "/create", method = RequestMethod.POST)
@ResponseBody
public Response<Backup> initiateBackup() {
final BackupManager manager = backupManagerTracker.service();
Backup backup = null;
if ( manager != null ) {
backup = manager.createBackup();
}
return Response.response(backup);
}
/**
* Import a backup into the system.
*
* @param file
* The backup archive to import. The archive should be one returned
* from a previous call to
* {@link BackupManager#exportBackupArchive(String, java.io.OutputStream)}.
* @return The response.
* @throws IOException
* If an IO error occurs.
*/
@RequestMapping(value = "/import", method = RequestMethod.POST)
@ResponseBody
public Response<Boolean> importBackup(@RequestParam("file") MultipartFile file) throws IOException {
Future<Backup> task = importTask;
if ( task != null && !task.isDone() ) {
return new Response<Boolean>(false, "422", "Import task already running", null);
}
final BackupManager manager = backupManagerTracker.service();
if ( manager == null ) {
return new Response<Boolean>(false, "500", "No backup manager available.", null);
}
Map<String, String> props = new HashMap<String, String>();
props.put(BackupManager.BACKUP_KEY, file.getName());
importTask = manager.importBackupArchive(file.getInputStream(), props);
return Response.response(true);
}
/**
* Check on the last import task, returning the backup {@code key} if the
* import completed.
*
* @return The response.
*/
@RequestMapping(value = "/import", method = RequestMethod.GET)
@ResponseBody
public Response<String> checkLastImport() {
Future<Backup> task = importTask;
try {
return Response.response(task != null && task.isDone() ? task.get().getKey() : null);
} catch ( ExecutionException e ) {
return new Response<String>(false, "500", "Import exception: " + e.getMessage(), null);
} catch ( InterruptedException e ) {
return new Response<String>(false, "500", "Interrupted", null);
}
}
/**
* Get information about a backup.
*
* @param key
* The key of the backup to get the information for.
* @param locale
* The desired locale of the information.
* @return The backup info response.
*/
@RequestMapping(value = "/inspect", method = RequestMethod.GET)
@ResponseBody
public Response<BackupInfo> inspectBackup(@RequestParam("key") String key, Locale locale) {
final BackupManager manager = backupManagerTracker.service();
if ( manager == null ) {
return new Response<BackupInfo>(false, "500", "No backup manager available.", null);
}
final BackupInfo info = manager.infoForBackup(key, locale);
if ( info == null ) {
return new Response<BackupInfo>(false, "404", "Backup not available for provided key.",
null);
}
return Response.response(info);
}
/**
* Restore a backup.
*
* @param options
* @return
*/
@RequestMapping(value = "/restore", method = RequestMethod.POST)
@ResponseBody
public Response<?> restoreBackup(BackupOptions options, Locale locale) {
final BackupManager manager = backupManagerTracker.service();
if ( manager == null ) {
return new Response<BackupInfo>(false, "500", "No backup manager available.", null);
}
final BackupService backupService = manager.activeBackupService();
if ( backupService == null ) {
return new Response<Backup>(false, "500", "No backup service available.", null);
}
final String backupKey = options.getKey();
if ( backupKey == null ) {
return new Response<Object>(false, "422", "No backup key provided.", null);
}
Backup backup = manager.activeBackupService().backupForKey(backupKey);
if ( backup == null ) {
return new Response<Object>(false, "404", "Backup not available.", null);
}
Map<String, String> props = options.asBackupManagerProperties();
manager.restoreBackup(backup, props);
shutdownSoon();
return new Response<Object>(true, null,
messageSource.getMessage("node.setup.restore.success", null, locale), null);
}
}