package org.carlspring.strongbox.cron.controller;
import org.carlspring.strongbox.controllers.BaseController;
import org.carlspring.strongbox.cron.api.jobs.GroovyCronJob;
import org.carlspring.strongbox.cron.domain.CronTaskConfiguration;
import org.carlspring.strongbox.cron.exceptions.CronTaskException;
import org.carlspring.strongbox.cron.quartz.GroovyScriptNames;
import org.carlspring.strongbox.cron.services.CronTaskConfigurationService;
import org.carlspring.strongbox.resource.ConfigurationResourceResolver;
import org.carlspring.strongbox.xml.parsers.GenericParser;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.MediaType;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Defines cron task processing API.
*
* @author Alex Oreshkevich
*/
@Controller
@RequestMapping("/configuration/crontasks")
@PreAuthorize("hasAuthority('ADMIN')")
public class CronTaskController
extends BaseController
{
private final GenericParser<CronTaskConfiguration> configParser = new GenericParser<>(CronTaskConfiguration.class);
@Inject
CronTaskConfigurationService cronTaskConfigurationService;
@ApiOperation(value = "Used to save the configuration", position = 0)
@ApiResponses(value = { @ApiResponse(code = 200, message = "The configuration was saved successfully."),
@ApiResponse(code = 400, message = "An error occurred.") })
@RequestMapping(value = "/cron",
method = RequestMethod.PUT,
consumes = { MediaType.APPLICATION_JSON,
MediaType.APPLICATION_XML }
)
public ResponseEntity saveConfiguration(@RequestBody CronTaskConfiguration cronTaskConfiguration)
{
try
{
logger.debug("Cron task configuration: " + objectMapper.writeValueAsString(cronTaskConfiguration));
logger.debug("Save Cron Task config call");
cronTaskConfigurationService.saveConfiguration(cronTaskConfiguration);
return ResponseEntity.ok().build();
}
catch (Exception e)
{
logger.error(e.getMessage(), e);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}
}
@ApiOperation(value = "Used to delete the configuration", position = 1)
@ApiResponses(value = { @ApiResponse(code = 200, message = "The configuration was deleted successfully."),
@ApiResponse(code = 400, message = "An error occurred.") })
@RequestMapping(value = "/cron", method = RequestMethod.DELETE)
public ResponseEntity deleteConfiguration(@RequestParam("name") String name)
{
final List<Exception> errors = new LinkedList<>();
cronTaskConfigurationService.getConfiguration(name)
.forEach(config -> {
try
{
cronTaskConfigurationService.deleteConfiguration(config);
if (config.contain("jobClass"))
{
Class c = Class.forName(config.getProperty("jobClass"));
Object classInstance = c.newInstance();
logger.debug("> " + c.getSuperclass().getCanonicalName());
if (classInstance instanceof GroovyCronJob)
{
File file = new File(config.getProperty("script.path"));
if (file.exists())
{
//noinspection ResultOfMethodCallIgnored
file.delete();
}
}
}
}
catch (Exception e)
{
errors.add(e);
}
});
if (!errors.isEmpty())
{
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors.get(0).getMessage());
}
return ResponseEntity.ok().body("Configuration " + name + " removed");
}
@ApiOperation(value = "Used to get the configuration on given cron task name", position = 2)
@ApiResponses(value = { @ApiResponse(code = 200, message = "The configuration retrieved successfully."),
@ApiResponse(code = 400, message = "An error occurred.") })
@RequestMapping(value = "/cron",
method = RequestMethod.GET,
produces = { MediaType.APPLICATION_JSON,
MediaType.APPLICATION_XML })
public ResponseEntity getConfiguration(@RequestParam("name") String name)
{
CronTaskConfiguration config = cronTaskConfigurationService.findOne(name);
if (config == null)
{
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body("Cron task config not found by this name!");
}
try
{
return ResponseEntity.ok(configParser.serialize(config));
}
catch (Exception e)
{
logger.error("Unable to serialize config", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
}
@ApiOperation(value = "Used to get list of all the configurations", position = 3)
@ApiResponses(value = { @ApiResponse(code = 200, message = "The all configurations retrieved successfully."),
@ApiResponse(code = 400, message = "An error occurred.") })
@RequestMapping(value = "/",
method = RequestMethod.GET,
produces = { MediaType.APPLICATION_JSON,
MediaType.APPLICATION_XML })
public ResponseEntity getConfigurations()
{
List<CronTaskConfiguration> configList = cronTaskConfigurationService.getConfigurations();
if (configList == null || configList.isEmpty())
{
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body("There are no cron task configs");
}
return ResponseEntity.ok(configList);
}
@ApiOperation(value = "Used to upload groovy script for groovy cron task", position = 4)
@ApiResponses(value = { @ApiResponse(code = 200, message = "The groovy script uploaded successfully."),
@ApiResponse(code = 400, message = "An error occurred.") })
@RequestMapping(value = "/cron/groovy", method = RequestMethod.PUT)
public ResponseEntity uploadGroovyScript(@RequestParam("cronName") String cronName,
HttpServletRequest request)
{
String fileName = request.getHeader("fileName");
if (!fileName.endsWith(".groovy"))
{
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body("The uploaded file must be a Groovy one!");
}
CronTaskConfiguration cronTaskConfiguration = cronTaskConfigurationService.findOne(cronName);
if (cronTaskConfiguration == null)
{
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body("Configuration not found by this name!");
}
logger.info(">> CRON NAME: " + cronTaskConfiguration.getName());
logger.info(">> Properties: " + cronTaskConfiguration.getProperties());
String path = ConfigurationResourceResolver.getVaultDirectory() + "/etc/conf/cron/groovy";
cronTaskConfiguration.addProperty("fileName", fileName);
cronTaskConfiguration.addProperty("jobClass", GroovyCronJob.class.getName());
cronTaskConfiguration.addProperty("script.path", path + "/" + fileName);
try
{
storeGroovyCronTask(request.getInputStream(), path, fileName);
cronTaskConfigurationService.saveConfiguration(cronTaskConfiguration);
}
catch (Exception e)
{
logger.error(e.getMessage(), e);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}
return ResponseEntity.ok().build();
}
@ApiOperation(value = "Used to get all groovy scripts names", position = 5)
@ApiResponses(value = { @ApiResponse(code = 200, message = "The groovy scripts named retrieved successfully."),
@ApiResponse(code = 400, message = "An error occurred.") })
@RequestMapping(value = "/groovy/names",
method = RequestMethod.GET,
produces = { MediaType.APPLICATION_JSON,
MediaType.APPLICATION_XML })
public ResponseEntity getGroovyScriptsName()
{
GroovyScriptNames groovyScriptNames = cronTaskConfigurationService.getGroovyScriptsName();
return ResponseEntity.ok(groovyScriptNames);
}
private void storeGroovyCronTask(InputStream is,
String dirPath,
String fileName)
throws CronTaskException
{
File dir = new File(dirPath);
if (!dir.exists())
{
//noinspection ResultOfMethodCallIgnored
dir.mkdirs();
}
File file = new File(dirPath + "/" + fileName);
try (OutputStream out = new FileOutputStream(file))
{
int read = 0;
byte[] bytes = new byte[1024];
while ((read = is.read(bytes)) != -1)
{
out.write(bytes, 0, read);
}
out.flush();
}
catch (IOException e)
{
throw new CronTaskException(e);
}
}
}