| /** |
| * |
| * 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.net.MalformedURLException |
| import java.net.URL |
| import java.nio.file.Files |
| import java.nio.file.Paths |
| import java.text.ParseException |
| import java.util.HashSet |
| import org.eclipse.osbp.utils.common.SystemInformation |
| import org.eclipse.osbp.xtext.datainterchange.DataInterchangeFile |
| import org.eclipse.osbp.xtext.datainterchange.DataInterchangeFileCSV |
| import org.eclipse.osbp.xtext.datainterchange.DataInterchangeFileEDI |
| import org.eclipse.osbp.xtext.datainterchange.DataInterchangeFileXML |
| 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.SignalHandler |
| 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.TriggerFile |
| import org.eclipse.osbp.xtext.signal.WeeklyScheduler |
| import org.eclipse.osbp.xtext.signal.common.OSBPSignalConstants |
| import org.eclipse.xtext.validation.Check |
| import org.quartz.CronExpression |
| |
| import static org.eclipse.osbp.xtext.signal.common.OSBPSignalConstants.* |
| |
| /** |
| * This class contains custom validation rules. |
| * |
| * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation |
| */ |
| class SignalDSLValidator extends AbstractSignalDSLValidator { |
| |
| @Check |
| def checkDuplicateWatcherNames(SignalPackage pkg) { |
| var watchers = new HashSet<String>() |
| for (watcher : pkg.watchers) { |
| if (!watchers.contains(watcher.name)) { |
| watchers.add(watcher.name) |
| } else { |
| error("The watcher id has to be unique and [" + watcher.name + "] is already in use. Please change it.", |
| watcher, SignalDSLPackage.Literals.SIGNAL_WATCHER__NAME) |
| } |
| } |
| } |
| |
| @Check |
| def checkDuplicateHandlerNames(SignalWatcher watcher) { |
| var handlers = new HashSet<String>() |
| for (handler : watcher.handlers) { |
| if (!handlers.contains(handler.name)) { |
| handlers.add(handler.name) |
| } else { |
| error("The handler id has to be unique.", handler, SignalDSLPackage.Literals.SIGNAL_HANDLER__NAME) |
| } |
| } |
| } |
| |
| @Check |
| def boolean checkFileNameValidity(SignalHandler handler) { |
| for (interchange : handler.interchanges) { |
| if (interchange.dataRef !== null && interchange.fileName !== null && |
| interchange.fileName.length > FILE_EXTENSION_MIN_SIZE) { |
| if (!isExtensionValid(interchange.fileName)) { |
| error( |
| "The filename extension you have entered is not currently supported. Only file with either following extension are allowed: .csv .edi or .xml", |
| interchange, SignalDSLPackage.Literals.SIGNAL_DATAINTERCHANGE__FILE_NAME) |
| } |
| var allowed_extension = getValidExtensionToInterchange(interchange.dataRef.fileEndpoint) |
| if (allowed_extension !== null && |
| !isExtensionAllowedToInterchange(interchange.fileName, allowed_extension)) { |
| error( |
| "The filename extension you have entered is not valid with [" + interchange.dataRef.name + |
| "] definition. Only filename with " + allowed_extension + " as extension are allowed!", |
| interchange, SignalDSLPackage.Literals.SIGNAL_DATAINTERCHANGE__FILE_NAME) |
| } |
| val filename = interchange.fileName.substring(0, |
| interchange.fileName.length - (FILE_EXTENSION_MIN_SIZE)) |
| if (!isFileNameWithoutExtensionValid(filename)) { |
| error( |
| "The filename contains one or more of the following non-allowed characters / \\ : * ? > < \" ' | please change it.", |
| interchange, SignalDSLPackage.Literals.SIGNAL_DATAINTERCHANGE__FILE_NAME) |
| } |
| } |
| } |
| } |
| |
| def boolean isExtensionValid(String filename) { |
| return (filename.endsWith(CSV_EXTENSION) || filename.endsWith(CSV_EXTENSION.toUpperCase) || |
| filename.endsWith(EDI_EXTENSION) || filename.endsWith(EDI_EXTENSION.toUpperCase) || |
| filename.endsWith(XML_EXTENSION) || filename.endsWith(XML_EXTENSION.toUpperCase) |
| ) |
| } |
| |
| def boolean isExtensionAllowedToInterchange(String filename, String allowedextension) { |
| return (filename.endsWith(allowedextension) || filename.endsWith(allowedextension.toUpperCase)) |
| } |
| |
| def String getValidExtensionToInterchange(DataInterchangeFile file) { |
| if (file instanceof DataInterchangeFileCSV) { |
| return CSV_EXTENSION |
| } |
| if (file instanceof DataInterchangeFileEDI) { |
| return EDI_EXTENSION |
| } |
| if (file instanceof DataInterchangeFileXML) { |
| return XML_EXTENSION |
| } |
| return null |
| } |
| |
| def boolean isFileNameWithoutExtensionValid(String filename) { |
| if(SystemInformation.isWindowsOS()){ |
| return !filename.contains('/') && !filename.contains('\\') && !filename.contains(':') && ( !filename.contains('*') && !filename.contains('?') |
| && !filename.contains('>') && !filename.contains('<') && !filename.contains('"') && !filename.contains('|')) |
| //based on win10 allowed characters on 12.04.2018 |
| } |
| else if(SystemInformation.isMacOS()){ |
| return |
| !filename.contains('/') && !filename.contains('\\') && !filename.contains('-') && ( !filename.contains('*') && !filename.contains('?') |
| && !filename.contains('[') && !filename.contains(']') && !filename.contains('"') && !filename.contains('\'') && !filename.contains('{') && !filename.contains('}')) |
| // based on http://www.informit.com/articles/article.aspx?p=1144082&seqNum=5 accessed on 12.04.2018 |
| } |
| else if(SystemInformation.isUnixOS()){ |
| return |
| !filename.contains('/') && !filename.contains('\\') && !filename.contains(':') && ( !filename.contains('*') && !filename.contains('?') |
| && !filename.contains('>') && !filename.contains('<') && !filename.contains('"') && !filename.contains('|') |
| ) |
| } |
| return true |
| } |
| |
| @Check |
| def checkDuplicateDirectoryNames(SignalPackage pkg) { |
| var watcherdir = new HashSet<String>() |
| for (watcher : pkg.watchers) { |
| if (!watcherdir.contains(watcher.directory)) { |
| watcherdir.add(watcher.directory) |
| } else { |
| error("The watcher directory '" + watcher.directory + |
| "' is already in use. Please choose another directory.", watcher, |
| SignalDSLPackage.Literals.SIGNAL_WATCHER__DIRECTORY) |
| } |
| } |
| } |
| |
| @Check |
| def boolean checkDuplicateFileMasks(SignalWatcher watcher) { |
| var filemasks = new HashSet<String>() |
| for (handler : watcher.handlers) { |
| if (handler.triggerpolicy !== null && handler.triggerpolicy instanceof TriggerFile) { |
| var temp = handler.triggerpolicy as TriggerFile |
| if (!filemasks.contains(temp.filemask)) { |
| filemasks.add(temp.filemask) |
| } else { |
| error( |
| "This file mask is already in use, please change it.", |
| temp, SignalDSLPackage.Literals.TRIGGER_FILE__FILEMASK) |
| return true |
| } |
| } |
| } |
| return false |
| } |
| |
| @Check |
| def void checkSignalSchedulerValidity(SignalScheduler signal) { |
| if (signal.scheduler !== null && signal.scheduler instanceof CronScheduler) { |
| checkCronExpressionValidity(signal.scheduler as CronScheduler) |
| } else if (signal.scheduler !== null && signal.scheduler instanceof HourlyScheduler) { |
| checkHourlySchedulerValidity(signal.scheduler as HourlyScheduler) |
| } else if (signal.scheduler !== null && signal.scheduler instanceof DailyScheduler) { |
| checkDailySchedulerValidity(signal.scheduler as DailyScheduler) |
| } else if (signal.scheduler !== null && signal.scheduler instanceof WeeklyScheduler) { |
| checkWeeklySchedulerValidity(signal.scheduler as WeeklyScheduler) |
| } else if (signal.scheduler !== null && signal.scheduler instanceof MonthlyScheduler) { |
| checkMonthlySchedulerValidity(signal.scheduler 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 + |
| OSBPSignalConstants.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 checkURLValidity(SignalHandler handler) { |
| if(handler.eContainer instanceof SignalWatcher){ |
| var url = getDirectoryURL(((handler.eContainer as SignalWatcher).directory)) |
| if(url !== null && !url.protocol.equals("file") && (handler.triggerpolicy instanceof TriggerFile)){ |
| error("Only scheduler based handlers are allowed, since the watcher directory is not a file url.", handler, SignalDSLPackage.Literals.SIGNAL_HANDLER__TRIGGERPOLICY) |
| } |
| } |
| } |
| |
| def getDirectoryURL(String directory) { |
| try { |
| return new URL(directory); |
| } catch (MalformedURLException e1) { |
| if(e1.getMessage().startsWith("unknown protocol") || e1.getMessage().startsWith("no protocol")) { |
| try { |
| return Paths.get(directory).toUri().toURL(); |
| } catch (MalformedURLException e2) { |
| return null |
| } |
| } |
| } |
| return null |
| } |
| |
| @Check |
| def checkDirectoryValidity(SignalWatcher watcher) { |
| var url = getDirectoryURL(watcher.directory) |
| if(url !== null && url.protocol.equals("file") && !existsDirectory(watcher.directory)){ |
| error("This directory doesn't exist. Please correct the path you have entered.", watcher, SignalDSLPackage.Literals.SIGNAL_WATCHER__DIRECTORY) |
| } |
| } |
| |
| def boolean existsDirectory(String path) { |
| try { |
| return Files.isDirectory(Paths.get(path)); |
| } catch (Exception e) { } |
| return false; |
| } |
| } |