| /** |
| * |
| * 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 |
| } |
| |
| } |
| |