blob: 7ed539691d2bbe9d73dae266aa1d3728b9c41b44 [file] [log] [blame]
/**
*
* Copyright (c) 2011, 2018 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation
*
* generated by Xtext 2.11.0
*
*/
package org.eclipse.osbp.xtext.signal.validation
import java.nio.file.FileSystems
import java.nio.file.PathMatcher
import java.text.ParseException
import java.util.HashSet
import java.util.regex.PatternSyntaxException
import javax.inject.Inject
import org.eclipse.emf.common.util.EList
import org.eclipse.osbp.xtext.datainterchange.validation.DataDSLValidator
import org.eclipse.osbp.xtext.signal.CronScheduler
import org.eclipse.osbp.xtext.signal.DailyScheduler
import org.eclipse.osbp.xtext.signal.HourlyScheduler
import org.eclipse.osbp.xtext.signal.MonthlyScheduler
import org.eclipse.osbp.xtext.signal.SignalDSLPackage
import org.eclipse.osbp.xtext.signal.SignalDatainterchange
import org.eclipse.osbp.xtext.signal.SignalDefinition
import org.eclipse.osbp.xtext.signal.SignalPackage
import org.eclipse.osbp.xtext.signal.SignalScheduler
import org.eclipse.osbp.xtext.signal.SignalWatcher
import org.eclipse.osbp.xtext.signal.WatcherWithFileMask
import org.eclipse.osbp.xtext.signal.WatcherWithFileName
import org.eclipse.osbp.xtext.signal.WeeklyScheduler
import org.eclipse.osbp.xtext.signal.common.SignalConstants
import org.eclipse.osbp.xtext.signal.jvmmodel.SignalDSLJvmModelInferrer
import org.eclipse.xtext.validation.Check
import org.quartz.CronExpression
/**
* This class contains custom validation rules.
*
* See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation
*/
class SignalDSLValidator extends AbstractSignalDSLValidator {
@Inject extension DataDSLValidator dv
@Inject extension SignalDSLJvmModelInferrer jvm
@Check
def checkDuplicateWatcherNames(SignalPackage pkg) {
var signals = new HashSet<String>()
for (signal : pkg.signals) {
if (!signals.contains(signal.name)) {
signals.add(signal.name)
} else {
error("Watcher's and scheduler's ID have to be unique and [" + signal.name +
"] is already in use. Please change it.", signal, SignalDSLPackage.Literals.SIGNAL_DEFINITION__NAME)
}
}
}
@Check
def void checkSignalSchedulerValidity(SignalScheduler signal) {
if (signal.getSchedulertype !== null && signal.getSchedulertype instanceof CronScheduler) {
checkCronExpressionValidity(signal.getSchedulertype as CronScheduler)
} else if (signal.getSchedulertype !== null && signal.getSchedulertype instanceof HourlyScheduler) {
checkHourlySchedulerValidity(signal.getSchedulertype as HourlyScheduler)
} else if (signal.getSchedulertype !== null && signal.getSchedulertype instanceof DailyScheduler) {
checkDailySchedulerValidity(signal.getSchedulertype as DailyScheduler)
} else if (signal.getSchedulertype !== null && signal.getSchedulertype instanceof WeeklyScheduler) {
checkWeeklySchedulerValidity(signal.getSchedulertype as WeeklyScheduler)
} else if (signal.getSchedulertype !== null && signal.getSchedulertype instanceof MonthlyScheduler) {
checkMonthlySchedulerValidity(signal.getSchedulertype as MonthlyScheduler)
}
}
def void checkCronExpressionValidity(CronScheduler scheduler) {
var expression = scheduler.expression // format: s m h dm m dw
try {
if (!CronExpression.isValidExpression(expression)) {
CronExpression.validateExpression(expression)
}
} catch (ParseException exception) {
error("The cron expression you have entered is invalid.\n\n" + exception + SignalConstants.CRONEXP_NOTICE,
scheduler, SignalDSLPackage.Literals.CRON_SCHEDULER__EXPRESSION)
}
}
def void checkHourlySchedulerValidity(HourlyScheduler scheduler) {
if (!(scheduler.minute >= 0 && scheduler.minute <= 59)) {
error("The minute entry has to be between 0 and 59.", scheduler,
SignalDSLPackage.Literals.HOURLY_SCHEDULER__MINUTE)
}
}
def void checkDailySchedulerValidity(DailyScheduler scheduler) {
if (!(scheduler.hour >= 0 && scheduler.hour <= 23)) {
error("The hour entry has to be between 0 and 23.", scheduler,
SignalDSLPackage.Literals.DAILY_SCHEDULER__HOUR)
}
if (!(scheduler.minute >= 0 && scheduler.minute <= 59)) {
error("The minute entry has to be between 0 and 59.", scheduler,
SignalDSLPackage.Literals.DAILY_SCHEDULER__MINUTE)
}
}
def void checkWeeklySchedulerValidity(WeeklyScheduler scheduler) {
if (!(scheduler.hour >= 0 && scheduler.hour <= 23)) {
error("The hour entry has to be between 0 and 23.", scheduler,
SignalDSLPackage.Literals.WEEKLY_SCHEDULER__HOUR)
}
if (!(scheduler.minute >= 0 && scheduler.minute <= 59)) {
error("The minute entry has to be between 0 and 59.", scheduler,
SignalDSLPackage.Literals.WEEKLY_SCHEDULER__MINUTE)
}
}
def void checkMonthlySchedulerValidity(MonthlyScheduler scheduler) {
if (!(scheduler.dayofmonth >= 1 && scheduler.dayofmonth <= 31)) {
error("The hour entry has to be between 1 and 31.", scheduler,
SignalDSLPackage.Literals.MONTHLY_SCHEDULER__DAYOFMONTH)
}
if (!(scheduler.hour >= 0 && scheduler.hour <= 23)) {
error("The hour entry has to be between 0 and 23.", scheduler,
SignalDSLPackage.Literals.MONTHLY_SCHEDULER__HOUR)
}
if (!(scheduler.minute >= 0 && scheduler.minute <= 59)) {
error("The minute entry has to be between 0 and 59.", scheduler,
SignalDSLPackage.Literals.MONTHLY_SCHEDULER__MINUTE)
}
}
@Check
def void checkFilePolicy(SignalDefinition signal) {
if(signal instanceof SignalWatcher){
var watcher = signal.definition
if(watcher instanceof WatcherWithFileMask){
if (watcher.filemask !== null && !watcher.filemask.isEmpty && watcher.executiontype !== null) {
if (watcher.interchange === null) {
error("You must define the task, on which the file mask must be applied on.",
watcher, SignalDSLPackage.Literals.WATCHER_WITH_FILE_MASK__INTERCHANGE)
}
}
}
else if(watcher instanceof WatcherWithFileName){
if (watcher.filename !== null && !watcher.filename.isEmpty && watcher.executiontype !== null) {
if (watcher.interchanges.basedInterchangeDefined == 0) {
error("The task on which the file name must be applied on, have to be marked with the keyword 'applyon'.",
watcher, SignalDSLPackage.Literals.WATCHER_WITH_FILE_NAME__INTERCHANGES)
} else if (watcher.interchanges.basedInterchangeDefined > 1) {
error("Only one task may be marked with the keyword 'applyon'.", watcher,
SignalDSLPackage.Literals.WATCHER_WITH_FILE_NAME__INTERCHANGES)
}
}
}
}
else if(signal instanceof SignalScheduler){
if (signal.interchanges.basedInterchangeDefined >= 1) {
error("No task may be marked here with the keyword 'applyon'.", signal,
SignalDSLPackage.Literals.SIGNAL_SCHEDULER__INTERCHANGES)
}
}
}
def int basedInterchangeDefined(EList<SignalDatainterchange> interchanges) {
var count = 0
for (unit : interchanges) {
if (unit.baseinterchange) {
count++
}
}
return count
}
@Check
def void checkDuplicateFileMaskOrFileName(SignalPackage pck) {
var filemasks = new HashSet<String>()
for (signal : pck.signals) {
if(signal instanceof SignalWatcher){
var watcher = signal.definition
if(watcher instanceof WatcherWithFileMask){
if (!filemasks.contains(watcher.filemask)) {
filemasks.add(watcher.filemask)
} else {
error("This file mask is already in use in another watcher. Please change it.", watcher,
SignalDSLPackage.Literals.WATCHER_WITH_FILE_MASK__FILEMASK)
}
}
else if(watcher instanceof WatcherWithFileName){
if (!filemasks.contains(watcher.filename)) {
filemasks.add(watcher.filename)
} else {
error("This file name is already in use in another watcher. Please change it.", watcher,
SignalDSLPackage.Literals.WATCHER_WITH_FILE_NAME__FILENAME)
}
}
}
}
}
@Check
def void checkFileMaskAndFileNameValidity(SignalDefinition signal) {
checkFileNameValidityCheck(signal);
if(signal instanceof SignalWatcher){
var watcher = signal.definition
if(watcher instanceof WatcherWithFileMask){
if (watcher !== null && watcher.filemask !== null && !watcher.filemask.isEmpty) {
try {
FileSystems.^default.getPathMatcher("glob:" + watcher.filemask)
} catch (PatternSyntaxException exception) {
error("The pattern of this file mask is invalid, please change it. Error: " + exception.message,
watcher, SignalDSLPackage.Literals.WATCHER_WITH_FILE_MASK__FILEMASK)
} catch (UnsupportedOperationException exception) {
error("The pattern of this file mask is not recognized, please change it. Error: " + exception.message,
watcher, SignalDSLPackage.Literals.WATCHER_WITH_FILE_MASK__FILEMASK)
} catch (IllegalArgumentException exception) {
error("The pattern of this file mask is invalid, please change it. Error: " + exception.message,
watcher, SignalDSLPackage.Literals.WATCHER_WITH_FILE_MASK__FILEMASK)
}
}
}
}
}
def void checkFileNameValidityCheck(SignalDefinition signal){
if(signal instanceof SignalWatcher){
var watcher = signal.definition
if(watcher instanceof WatcherWithFileMask){
if (watcher !== null && watcher.filemask !== null && !watcher.filemask.isEmpty
&& watcher.interchange !== null && watcher.interchange.dataRef !== null) {
var baseinterchange = watcher.interchange.dataRef
if (baseinterchange !== null && baseinterchange.fileEndpoint !== null){
var allowed_extension = getValidExtensionToInterchange(baseinterchange.fileEndpoint)
if (allowed_extension !== null) {
if(allowed_extension.equals(CSV_EXTENSION) && !isExtensionAllowedForInterchange(watcher.filemask, allowed_extension)){
error("The file mask ["+watcher.filemask+"] you have entered is not valid. Only file masks ending with the extension "+allowed_extension+" are allowed for this watcher!",
watcher, SignalDSLPackage.Literals.WATCHER_WITH_FILE_MASK__FILEMASK)
}
else if (allowed_extension.equals(EDI_EXTENSION) && !isExtensionAllowedForInterchange(watcher.filemask, allowed_extension)){
error("The file mask ["+watcher.filemask+"] you have entered is not valid. Only file masks ending with the extension "+allowed_extension+" are allowed for this watcher!",
watcher, SignalDSLPackage.Literals.WATCHER_WITH_FILE_MASK__FILEMASK)
}
else if (allowed_extension.equals(XML_EXTENSION) && !isExtensionAllowedForInterchange(watcher.filemask, allowed_extension)){
error("The file mask ["+watcher.filemask+"] you have entered is not valid. Only file masks ending with the extension "+allowed_extension+" are allowed for this watcher!",
watcher, SignalDSLPackage.Literals.WATCHER_WITH_FILE_MASK__FILEMASK)
}
}
if (!isExtensionValid(watcher.filemask)) {
error("The file mask extension you have entered is not currently supported. Only file masks ending with either one of following extension are allowed: '.csv' '.edi' or '.xml' .",
watcher, SignalDSLPackage.Literals.WATCHER_WITH_FILE_MASK__FILEMASK)
}
}
}
}
else if(watcher instanceof WatcherWithFileName){
if (watcher !== null && watcher.filename !== null && !watcher.filename.isEmpty && watcher.interchanges !== null
&& !watcher.interchanges.empty && signal.getBaseInterchange !== null) {
var baseinterchange = signal.getBaseInterchange.dataRef
if (baseinterchange !== null && baseinterchange.fileEndpoint !== null){
var allowed_extension = getValidExtensionToInterchange(baseinterchange.fileEndpoint)
if (allowed_extension !== null) {
if(allowed_extension.equals(CSV_EXTENSION) && !isExtensionAllowedForInterchange(watcher.filename, allowed_extension)){
error("The file name ["+watcher.filename+"] you have entered is not valid. Only file names ending with the extension "+allowed_extension+" are allowed for this watcher!",
watcher, SignalDSLPackage.Literals.WATCHER_WITH_FILE_NAME__FILENAME)
}
else if (allowed_extension.equals(EDI_EXTENSION) && !isExtensionAllowedForInterchange(watcher.filename, allowed_extension)){
error("The file name ["+watcher.filename+"] you have entered is not valid. Only file names ending with the extension "+allowed_extension+" are allowed for this watcher!",
watcher, SignalDSLPackage.Literals.WATCHER_WITH_FILE_NAME__FILENAME)
}
else if (allowed_extension.equals(XML_EXTENSION) && !isExtensionAllowedForInterchange(watcher.filename, allowed_extension)){
error("The file name ["+watcher.filename+"] you have entered is not valid. Only file names ending with the extension "+allowed_extension+" are allowed for this watcher!",
watcher, SignalDSLPackage.Literals.WATCHER_WITH_FILE_NAME__FILENAME)
}
}
else{
error("The file name extension you have entered is not currently supported. Only file names ending with either one of following extension are allowed: '.csv' '.edi' or '.xml' .",
watcher, SignalDSLPackage.Literals.WATCHER_WITH_FILE_NAME__FILENAME)
}
}
}
}
}
}
// // TODO need to be tested and completed
// @Check
// def void arePatternMatching(SignalPackage pck) {
// for (signal : pck.signals) {
// if (signal instanceof SignalWatcher) {
// var watcher = signal.definition
// if (watcher instanceof WatcherWithFileMask) {
// if (watcher.filemask.isFileMaskValid !== null) {
// var temp = escapeCharacters(watcher.filemask)
// for (signal2 : pck.signals) {
//
// if (signal2 instanceof SignalWatcher) {
// var watcher2 = signal2.definition
//
// if (watcher2 instanceof WatcherWithFileMask) {
// if (watcher2 !== watcher && watcher2.filemask.isFileMaskValid !== null) {
// try{
// // check if they are the same
// if (watcher.filemask.equals(watcher2.filemask)) {
// error("This file mask is already in use, please change it.", watcher,
// SignalDSLPackage.Literals.WATCHER_WITH_FILE_MASK__FILEMASK)
// } else if (watcher2.filemask.isFileMaskValid.matches(Paths.get(temp))) {
// warning(
// "This file mask is matched by the one [" + signal2.filemask +
// "] defined in the watcher named [" + signal2.name +
// "]. This may cause unintended effects, if the monitored directories are the same. We recommend you to change it, and define a unique file mask for this watcher instead.",
// watcher, SignalDSLPackage.Literals.WATCHER_WITH_FILE_MASK__FILEMASK)
// }
// }
// catch(InvalidPathException e){
// warning("One of those two file masks is not valid! File mask #1 [" + watcher.filemask +"] from watcher [" + watcher.name +"] and file mask #2 [" + watcher2.filemask +"] from watcher [" + watcher2.name
// +"] This may cause unintended effects. We recommend you to review both file masks, and define a unique file mask for this watcher instead.",
// watcher, SignalDSLPackage.Literals.WATCHER_WITH_FILE_MASK__FILEMASK)
// }
//
// }
// }
// }
// }
// }
// }
// }
// }
// }
def PathMatcher isFileMaskValid(String filemask) {
if (filemask !== null && !filemask.isEmpty) {
try {
return FileSystems.^default.getPathMatcher("glob:" + filemask)
} catch (Exception exception) {
return null
}
}
return null
}
def String escapeCharacters(String pattern) {
if (pattern !== null && !pattern.isEmpty) {
var result = pattern
if (result.indexOf('*') !== -1) {
result = result.replaceAll("\\*", "")
}
if (result.contains("\\")) {
result = result.replaceAll("\\", "")
}
if (result.contains("?")) {
result = result.replaceAll("\\?", "")
}
return result
}
return null
}
}