blob: 1ce0fc0fdce80a2618e6ec01cbb2092fd9b972df [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 v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation
*
* generated by Xtext 2.11.0
*
*/
package org.eclipse.osbp.xtext.signal.jvmmodel
import java.io.IOException
import java.nio.file.Path
import java.util.HashSet
import javax.inject.Inject
import org.eclipse.osbp.core.api.persistence.IPersistenceService
import org.eclipse.osbp.datainterchange.api.IDataInterchange
import org.eclipse.osbp.dsl.common.xtext.extensions.AnnotationExtension
import org.eclipse.osbp.ui.api.customfields.IBlobService
import org.eclipse.osbp.ui.api.useraccess.IUserAccessService
import org.eclipse.osbp.xtext.datainterchange.DataInterchange
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.datainterchange.common.WorkerThreadRunnable.Direction
import org.eclipse.osbp.xtext.signal.ListTransfer
import org.eclipse.osbp.xtext.signal.SignalActionEnum
import org.eclipse.osbp.xtext.signal.SignalDSLPackage
import org.eclipse.osbp.xtext.signal.SignalDatainterchange
import org.eclipse.osbp.xtext.signal.SignalExecutionTypeEnum
import org.eclipse.osbp.xtext.signal.SignalPackage
import org.eclipse.osbp.xtext.signal.SignalWatcher
import org.eclipse.osbp.xtext.signal.SingleTransfer
import org.eclipse.osbp.xtext.signal.common.OSBPSignalWatcher
import org.eclipse.xtext.common.types.JvmField
import org.eclipse.xtext.common.types.JvmGenericType
import org.eclipse.xtext.common.types.JvmVisibility
import org.eclipse.xtext.naming.IQualifiedNameProvider
import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer
import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder
import org.osgi.service.component.annotations.Activate
import org.osgi.service.component.annotations.Component
import org.osgi.service.component.annotations.Deactivate
import org.osgi.service.component.annotations.Reference
import org.osgi.service.component.annotations.ReferenceCardinality
import org.osgi.service.component.annotations.ReferencePolicy
import org.slf4j.Logger
import java.util.concurrent.ExecutorService
/**
* <p>Infers a JVM model from the source model.</p>
*
* <p>The JVM model should contain all elements that would appear in the Java code
* which is generated from the source model. Other models link against the JVM model rather than the source model.</p>
*/
class SignalDSLJvmModelInferrer extends AbstractModelInferrer {
/**
* convenience API to build and initialize JVM types and their members.
*/
@Inject extension JvmTypesBuilder
@Inject extension IQualifiedNameProvider
@Inject extension SignalModelGenerator sg
@Inject extension AnnotationExtension
var HashSet<String> operationlist
/**
* infer model on package base. Will be called for every defined package.
*
* @param dataInterchangePackage
* An instance of {@link SignalDSLPackage}
* @param acceptor
* the xtext acceptor interface
* @param isPreIndexingPhase
* true if in preindexing phase
*/
def dispatch void infer(SignalPackage signalPackage, IJvmDeclaredTypeAcceptor acceptor,
boolean isPreIndexingPhase) {
val pckgName = signalPackage.name;
// create watchers
for (watcher : signalPackage.watchers) {
var watcherClass = watcher.toClass(watcher.fullyQualifiedName)
watcherClass.simpleName = watcher.name.toFirstUpper + "Watcher"
watcherClass.packageName = pckgName
acceptor.accept(watcherClass, [
superTypes += _typeReferenceBuilder.typeRef(OSBPSignalWatcher)
var annotationRef = _annotationTypesBuilder.annotationRef(typeof(Component))
annotationRef.addAnnAttr(signalPackage, "immediate", Boolean.TRUE)
annotations += annotationRef
it.fileHeader = signalPackage.documentation
it.toWatcherFields(watcher)
it.toWatcherConstructor(watcher)
it.toWatcherOperations(watcher)
it.toBinderOperations(watcher)
])
}
}
def void toBinderOperations(JvmGenericType type, SignalWatcher watcher) {
// // getter sor services
// type.members += watcher.toMethod("getDataInterchange", _typeReferenceBuilder.typeRef(IDataInterchange), [
// visibility = JvmVisibility.PUBLIC
// static = true
// body = [append('''return dataInterchange;''')]
// ])
// type.members += watcher.toMethod("getBlobService", _typeReferenceBuilder.typeRef(IBlobService), [
// visibility = JvmVisibility.PUBLIC
// static = true
// body = [append('''return blobService;''')]
// ])
// type.members += watcher.toMethod("getPersistenceService", _typeReferenceBuilder.typeRef(IPersistenceService), [
// visibility = JvmVisibility.PUBLIC
// static = true
// body = [append('''return persistenceService;''')]
// ])
// type.members += watcher.toMethod("getUserAccessService", _typeReferenceBuilder.typeRef(IUserAccessService), [
// visibility = JvmVisibility.PUBLIC
// static = true
// body = [append('''return userAccessService;''')]
// ])
// bind datainterchange service
type.members += watcher.toMethod("bindDataInterchangeMethod", _typeReferenceBuilder.typeRef(Void::TYPE), [
var annotationRef = _annotationTypesBuilder.annotationRef(typeof(Reference))
annotationRef.addAnnAttr(watcher, "cardinality", ReferenceCardinality.MANDATORY)
annotationRef.addAnnAttr(watcher, "policy", ReferencePolicy.STATIC)
annotations += annotationRef
visibility = JvmVisibility.PUBLIC
synchronized = true
parameters += watcher.toParameter("dataInterchange", _typeReferenceBuilder.typeRef(IDataInterchange))
body = [append('''
this.dataInterchange = dataInterchange;
log.debug("Signal DataInterchange bound");''')]
])
// unbind datainterchange service
type.members += watcher.toMethod("unbindDataInterchangeMethod", _typeReferenceBuilder.typeRef(Void::TYPE), [
visibility = JvmVisibility.PUBLIC
synchronized = true
parameters += watcher.toParameter("dataInterchange", _typeReferenceBuilder.typeRef(IDataInterchange))
body = [
append('''
this.dataInterchange = null;
log.debug("Signal DataInterchange unbound");
''')
]
])
// bind blob service
type.members += watcher.toMethod("bindBlobMethod", _typeReferenceBuilder.typeRef(Void::TYPE), [
var annotationRef = _annotationTypesBuilder.annotationRef(typeof(Reference))
annotationRef.addAnnAttr(watcher, "cardinality", ReferenceCardinality.MANDATORY)
annotationRef.addAnnAttr(watcher, "policy", ReferencePolicy.STATIC)
annotations += annotationRef
visibility = JvmVisibility.PUBLIC
synchronized = true
parameters += watcher.toParameter("blobService", _typeReferenceBuilder.typeRef(IBlobService))
body = [
append(
'''
this.blobService = blobService;
log.debug("Signal BlobService bound");
''')
]
])
// unbind blob service
type.members += watcher.toMethod("unbindBlobMethod", _typeReferenceBuilder.typeRef(Void::TYPE), [
visibility = JvmVisibility.PUBLIC
synchronized = true
parameters += watcher.toParameter("blobService", _typeReferenceBuilder.typeRef(IBlobService))
body = [
append(
'''
this.blobService = null;
log.debug("Signal BlobService unbound");
''')
]
])
// bind persistence service
type.members += watcher.toMethod("bindPersistenceMethod", _typeReferenceBuilder.typeRef(Void::TYPE), [
var annotationRef = _annotationTypesBuilder.annotationRef(typeof(Reference))
annotationRef.addAnnAttr(watcher, "cardinality", ReferenceCardinality.MANDATORY)
annotationRef.addAnnAttr(watcher, "policy", ReferencePolicy.STATIC)
annotations += annotationRef
visibility = JvmVisibility.PUBLIC
synchronized = true
parameters += watcher.toParameter("persistenceService", _typeReferenceBuilder.typeRef(IPersistenceService))
body = [
append(
'''
this.persistenceService = persistenceService;
log.debug("Signal PersistenceService bound");
''')
]
])
// unbind persistence service
type.members += watcher.toMethod("unbindPersistenceMethod", _typeReferenceBuilder.typeRef(Void::TYPE), [
visibility = JvmVisibility.PUBLIC
synchronized = true
parameters += watcher.toParameter("persistenceService", _typeReferenceBuilder.typeRef(IPersistenceService))
body = [
append(
'''
this.persistenceService = null;
log.debug("Signal PersistenceService unbound");
''')
]
])
// bind userAccessService
type.members += watcher.toMethod("bindUserAccessMethod", _typeReferenceBuilder.typeRef(Void::TYPE), [
var annotationRef = _annotationTypesBuilder.annotationRef(typeof(Reference))
annotationRef.addAnnAttr(watcher, "cardinality", ReferenceCardinality.MANDATORY)
annotationRef.addAnnAttr(watcher, "policy", ReferencePolicy.STATIC)
annotations += annotationRef
visibility = JvmVisibility.PUBLIC
synchronized = true
parameters += watcher.toParameter("userAccessService", _typeReferenceBuilder.typeRef(IUserAccessService))
body = [
append(
'''
this.userAccessService = userAccessService;
log.debug("Signal UserAccessService bound");
''')
]
])
// unbind userAccessService
type.members += watcher.toMethod("unbindUserAccessMethod", _typeReferenceBuilder.typeRef(Void::TYPE), [
visibility = JvmVisibility.PUBLIC
synchronized = true
parameters += watcher.toParameter("userAccessService", _typeReferenceBuilder.typeRef(IUserAccessService))
body = [
append(
'''
this.userAccessService = null;
log.debug("Signal UserAccessService unbound");''')
]
])
}
def String getFileURL(DataInterchange dataInterchange) {
switch (dataInterchange.fileEndpoint) {
DataInterchangeFileXML: return (dataInterchange.fileEndpoint as DataInterchangeFileXML).fileURL
DataInterchangeFileCSV: return (dataInterchange.fileEndpoint as DataInterchangeFileCSV).fileURL
DataInterchangeFileEDI: return (dataInterchange.fileEndpoint as DataInterchangeFileEDI).fileURL
}
return ""
}
def String getDefaultVariableName(DataInterchange dataInterchange) {
return dataInterchange.name.toFirstLower
}
def String getBasicRunConfiguration(DataInterchange dataInterchange, boolean fqClass,
Direction direction, boolean asynch) {
var className = ""
if (fqClass) {
className = dataInterchange.fullyQualifiedName.toString
} else {
className = dataInterchange.name
}
return '''
«className» «dataInterchange.getDefaultVariableName» = new «className»();
«dataInterchange.getDefaultVariableName».setFileURL(directory + FileSystems.getDefault().getSeparator() + filename);
«dataInterchange.getDefaultVariableName».setPersistenceService(persistenceService);
«dataInterchange.getDefaultVariableName».setDataInterchange(dataInterchange);
«dataInterchange.getDefaultVariableName».setBlobService(blobService);
«dataInterchange.getDefaultVariableName()».setDirection(WorkerThreadRunnable.Direction.«direction.name.toUpperCase»);
return «dataInterchange.getDefaultVariableName»;'''
}
def void toWatcherOperations(JvmGenericType type, SignalWatcher watcher) {
// creating the handleEvent operation, detailing the order
// of execution of each operation after a signal is caught
type.members += watcher.toMethod("handleEvent", _typeReferenceBuilder.typeRef(Void::TYPE), [
annotations += _annotationTypesBuilder.annotationRef(Override)
parameters += watcher.toParameter("event", _typeReferenceBuilder.typeRef("WatchEvent<Path>"))
parameters += watcher.toParameter("file", _typeReferenceBuilder.typeRef(Path))
body = [append('''«watcher.handleEvent»''')]
])
// creating executetask operation
type.members += watcher.toMethod("executeTasks", _typeReferenceBuilder.typeRef(Void::TYPE), [
parameters += watcher.toParameter("interchanges", _typeReferenceBuilder.typeRef("ArrayList<WorkerThreadRunnable>"))
parameters += watcher.toParameter("synchronous", _typeReferenceBuilder.typeRef(boolean))
body = [append('''«watcher.executeTasks»''')]
])
// create all handlers operations
operationlist = new HashSet()
if (watcher !== null && watcher.handlers !== null && !watcher.handlers.empty) {
for (handler : watcher.handlers) {
if (handler.data instanceof SingleTransfer) {
// only one interchange is available
val transferdata = handler.data as SingleTransfer
createAppropriateInterchangeOperations(type, watcher, transferdata.interchange)
} else {
// a list of interchange is available
val transferdata = handler.data as ListTransfer
for (interchange : transferdata.interchanges) {
createAppropriateInterchangeOperations(type, watcher, interchange)
}
}
}
}
// create watcher initTasksLists
type.members += watcher.toMethod("initTasksLists", _typeReferenceBuilder.typeRef(Void::TYPE), [
body = [append('''«watcher.initTasksLists»''')]
])
// create watcher stopthread
type.members += watcher.toMethod("stopThread", _typeReferenceBuilder.typeRef(Void::TYPE), [
body = [append('''active = false;''')]
])
// create watcher activate
type.members += watcher.toMethod("activate", _typeReferenceBuilder.typeRef(Void::TYPE), [
annotations += _annotationTypesBuilder.annotationRef(Activate)
body = [append('''«watcher.activate»''')]
])
// create watcher deactivate
type.members += watcher.toMethod("deactivate", _typeReferenceBuilder.typeRef(Void::TYPE), [
annotations += _annotationTypesBuilder.annotationRef(Deactivate)
body = [append('''«watcher.deactivate»''')]
])
}
def String executeTasks(SignalWatcher watcher){
return '''
for (WorkerThreadRunnable interchange : interchanges) {
if(synchronous){
//Making sure that the current task is done before continuing
try {
log.debug("Watcher: Start "+interchange.getDirection()+" for interchange "+interchange.getName()+"!");
executorService.submit(interchange).get();
log.debug("Watcher: "+interchange.getDirection()+" for "+ interchange.getName() + " successfully ended!");
} catch (Exception e) {
log.debug("Watcher: "+interchange.getDirection()+" for "+ interchange.getName() + " interupted!\n"+e.getMessage());
}
}
else{
// Just executre the task and move onto the next one
executorService.execute(interchange);
}
}'''
}
def String handleEvent(SignalWatcher watcher) {
var result = '''
// get what to do based on the filename
String filemask = isFileMaskValid(file.getFileName().toString(), event.kind());
if(filemask != null){
switch (filemask) {
'''
for(handler : watcher.handlers){
var is_synch = (handler.executiontype ?: SignalExecutionTypeEnum.SYNC).equals(SignalExecutionTypeEnum.SYNC)
if(handler.data instanceof SingleTransfer){
var handlerdata = handler.data as SingleTransfer
result = result.concat(
'''
case "«handler.name+"|"+handler.filemask»":
«if(is_synch){
'''
try {
log.debug("Watcher: Start «handlerdata.interchange.dataAction.literal.toFirstUpper» for interchange «handlerdata.interchange.dataRef.name.toFirstUpper»!");
executorService.submithandlerdata.interchange.getAppropriateInterchangeOperationName»(directory + "«handlerdata.interchange.fileName»")).get();
log.debug("Watcher: «handlerdata.interchange.dataAction.literal.toFirstUpper» for interchange «handlerdata.interchange.dataRef.name.toFirstUpper» successfully ended!");
}catch (Exception e) {
log.debug("Watcher: «handlerdata.interchange.dataAction.literal.toFirstUpper» for interchange «handlerdata.interchange.dataRef.name.toFirstUpper» interupted!\n"+e.getMessage());
} break;
'''
}else{
'''executorService.executehandlerdata.interchange.getAppropriateInterchangeOperationName»(directory + "«handlerdata.interchange.fileName»")); break;'''
''')
}else{
result = result.concat(
'''
case "«handler.name+"|"+handler.filemask»":
executeTasks(listOfTasks.get("«handler.name+"|"+handler.filemask»"), «is_synch»); break;
''')
}
}
result = result.concat(
'''
default: break;
}
}
else{
log.debug("No action executed for file ["+file+"] on event ["+event.kind().name()+"].");
}''')
return result
}
def void toWatcherConstructor(JvmGenericType type, SignalWatcher watcher) {
type.members += watcher.toConstructor [
exceptions += _typeReferenceBuilder.typeRef(IOException)
body = [append(
'''
super();
executorService = Executors.newFixedThreadPool(10);''')]
]
}
def String initTasksLists(SignalWatcher watcher){
var result = '''
ArrayList<WorkerThreadRunnable> data = null;
listOfTasks = new HashMap<>();
'''
for(handler : watcher.handlers){
if(handler.data instanceof ListTransfer){
var handlerdata = handler.data as ListTransfer
result = result.concat('''data = new ArrayList<WorkerThreadRunnable>();
''')
for (interchange : handlerdata.interchanges) {
result = result.concat('''data.add(«interchange.appropriateInterchangeOperationName»("«interchange.fileName»"));
''')
}
result = result.concat('''listOfTasks.put("«handler.name+"|"+handler.filemask»", data);
''');
}
result = result.concat('''
addFilemaskAndAction("«handler.name+"|"+handler.filemask»", SignalHandlerTypeEnum.«handler.actionType.literal.toUpperCase»);
''')
}
return result
}
def String getAppropriateInterchangeOperationName(SignalDatainterchange interchange) {
var operation_name = ""
if (interchange.dataAction == SignalActionEnum.DATAIMPORT && interchange.dataRef !== null) {
operation_name = "import" + interchange.dataRef.name.toFirstUpper
} else if (interchange.dataRef !== null) {
operation_name = "export" + interchange.dataRef.name.toFirstUpper
}
return operation_name
}
def createAppropriateInterchangeOperations(JvmGenericType type, SignalWatcher watcher, SignalDatainterchange interchange) {
var operationname = interchange.appropriateInterchangeOperationName
//create the operation only if it has not already been created
if(!operationlist.contains(operationname)){
if(interchange.dataAction == SignalActionEnum.DATAIMPORT){
type.members +=
watcher.toMethod(operationname, _typeReferenceBuilder.typeRef("WorkerThreadRunnable"),
[
parameters += watcher.toParameter("filename", _typeReferenceBuilder.typeRef(String))
body = [append('''«interchange.dataRef.getBasicRunConfiguration(true, Direction.IMPORT, false)»''')]
])
}
else{
type.members +=
watcher.toMethod(operationname, _typeReferenceBuilder.typeRef("WorkerThreadRunnable"),
[
parameters += watcher.toParameter("filename", _typeReferenceBuilder.typeRef(String))
body = [append('''«interchange.dataRef.getBasicRunConfiguration(true, Direction.EXPORT, false)»''')]
])
}
operationlist.add(operationname)
}
}
def void toWatcherFields(JvmGenericType type, SignalWatcher watcher) {
var JvmField field = null
// create logger field
field = watcher.toField("log", _typeReferenceBuilder.typeRef(Logger)) [
visibility = JvmVisibility::PRIVATE
setInitializer([append('''LoggerFactory.getLogger("watcher")''')])
]
type.members += field
// create directory field
field = watcher.toField("directory", _typeReferenceBuilder.typeRef(String)) [
visibility = JvmVisibility::PRIVATE
setInitializer([append('''"«watcher.directory»"''')])
]
type.members += field
// create thread field
field = watcher.toField("thread", _typeReferenceBuilder.typeRef(Thread)) [
visibility = JvmVisibility::PRIVATE
]
type.members += field
// create active field
field = watcher.toField("active", _typeReferenceBuilder.typeRef(boolean)) [
setInitializer([append('''true''')])
visibility = JvmVisibility::PRIVATE
]
type.members += field
// create active field
field = watcher.toField("executorService", _typeReferenceBuilder.typeRef(ExecutorService)) [
visibility = JvmVisibility::PRIVATE
static = true
]
type.members += field
// create listOftasks field
field = watcher.toField("listOfTasks",
_typeReferenceBuilder.typeRef("Map<String, ArrayList<WorkerThreadRunnable>>")) [
visibility = JvmVisibility::PRIVATE
]
type.members += field
// create persistence service field
field = watcher.toField("persistenceService", _typeReferenceBuilder.typeRef(IPersistenceService))
field.static = true
field.visibility = JvmVisibility::PRIVATE
type.members += field
// create datainterchange service field
field = watcher.toField("dataInterchange", _typeReferenceBuilder.typeRef(IDataInterchange))
field.static = true
field.visibility = JvmVisibility::PRIVATE
type.members += field
// create user service field
field = watcher.toField("userAccessService", _typeReferenceBuilder.typeRef(IUserAccessService))
field.static = true
field.visibility = JvmVisibility::PRIVATE
type.members += field
// create blob service field
field = watcher.toField("blobService", _typeReferenceBuilder.typeRef(IBlobService))
field.static = true
field.visibility = JvmVisibility::PRIVATE
type.members += field
}
def String getActivate(SignalWatcher watcher) {
return '''
thread = new Thread() {
@Override
public void run() {
//«watcher.name.toFirstUpper+"Watcher"» watcherservice = null;
try {
//watcherservice = new «watcher.name.toFirstUpper+"Watcher"»();
//watcherservice.setSignals(Arrays.asList(SignalTypeEnum.«watcher.signal.literal.toUpperCase»));
//watcherservice.registerPathToWatcher(Paths.get(directory));
setSignals(Arrays.asList(SignalTypeEnum.«watcher.signal.literal.toUpperCase»));
registerPathToWatcher(Paths.get(directory));
while (active) {
log.debug("Start watcher Service «watcher.name.toFirstUpper+"Watcher"»");
//watcherservice.processEvents();
initTasksLists();
processEvents();
}
} catch (Exception e) {
log.debug("Thread interrupted " + e.getMessage());
//watcherservice.closeWatcher();
closeWatcher();
}
}
};
thread.start();'''
}
def String getDeactivate(SignalWatcher watcher) {
return '''
try {
stopThread();
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}'''
}
}