blob: 91ef3c2e83077347a2bb964e6191fb68389b753e [file] [log] [blame]
/**
*
* Copyright (c) 2011, 2016 - 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
*
*
* This copyright notice shows up in the generated Java code
*
*/
package org.eclipse.osbp.xtext.messagedsl.jvmmodel
import com.google.common.base.CaseFormat
import javax.inject.Inject
import org.eclipse.osbp.xtext.messagedsl.MessageCategory
import org.eclipse.osbp.xtext.messagedsl.MessageItem
import org.eclipse.osbp.xtext.messagedsl.MessageModel
import org.eclipse.osbp.xtext.messagedsl.MessagePackage
import org.eclipse.osbp.xtext.messagedsl.MessageText
import org.eclipse.osbp.xtext.messagedsl.common.IMessageCategory
import org.eclipse.osbp.xtext.messagedsl.common.Message
import org.eclipse.xtext.common.types.JvmDeclaredType
import org.eclipse.xtext.common.types.JvmOperation
import org.eclipse.xtext.common.types.JvmVisibility
import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer
import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor
import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor.IPostIndexingInitializing
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder
import org.slf4j.Logger
/**
* <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 MessageDslJvmModelInferrer extends AbstractModelInferrer {
/**
* convenience API to build and initialize JVM types and their members.
*/
@Inject extension JvmTypesBuilder
/**
* The dispatch method {@code infer} is called for each instance of the
* given element's type that is contained in a resource.
*
* @param element
* the model to create one or more
* {@link JvmDeclaredType declared
* types} from.
* @param acceptor
* each created
* {@link JvmDeclaredType type}
* without a container should be passed to the acceptor in order
* get attached to the current resource. The acceptor's
* {@link IJvmDeclaredTypeAcceptor#accept(org.eclipse.xtext.common.types.JvmDeclaredType)
* accept(..)} method takes the constructed empty type for the
* pre-indexing phase. This one is further initialized in the
* indexing phase using the closure you pass to the returned
* {@link IPostIndexingInitializing#initializeLater(org.eclipse.xtext.xbase.lib.Procedures.Procedure1)
* initializeLater(..)}.
* @param isPreIndexingPhase
* whether the method is called in a pre-indexing phase, i.e.
* when the global index is not yet fully updated. You must not
* rely on linking using the index if isPreIndexingPhase is
* <code>true</code>.
*/
def dispatch void infer(MessageModel model, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
model.pckg.categories.forEach [ category |
acceptor.accept(model.toClass('''«category.getFQMessageClass»''')) [
superTypes += _typeReferenceBuilder.typeRef(IMessageCategory)
// @see org.eclipse.osbp.utils.constants.GeneratorConstants.GeneratorConstants
documentation = '''<b>This class was auto generated! Leave it unmodified to avoid unpredictable results!</b><br>
«category.documentation»
'''
final = true
it.fileHeader = model.pckg.documentation
category.items.forEach [ item |
it.members += toMethod(false, model, category, item, acceptor)
it.members += toMethod(true, model, category, item, acceptor)
]
]
]
}
/**
* return the simple generated class name for the message category
*/
public def static String getSimpleMessageClass(MessageCategory category) {
return '''«category.name»Message'''
}
/**
* return the fully qualified generated class name for the message category
*/
public def static String getFQMessageClass(MessageCategory category) {
return '''«(category.eContainer as MessagePackage).name».«category.getSimpleMessageClass»'''
}
/**
* return the fully qualified generated class name for the message item
*/
public def static String getFQMessageClass(MessageItem item) {
return (item.eContainer as MessageCategory).getFQMessageClass
}
/**
* return the generated method name for the message item
*/
public def static String getMethodName(MessageItem item) {
return item.name
}
def JvmOperation toMethod(boolean withLogger, MessageModel model, MessageCategory category,
MessageItem item, IJvmDeclaredTypeAcceptor acceptor) {
return model.toMethod('''«item.name.toFirstLower»''', _typeReferenceBuilder.typeRef(Message)) [
val fqMessageClass = item.FQMessageClass
var docCompiled = "" as String
if (item.documentation instanceof String) {
docCompiled = '''«docCompiled»
«item.documentation»<br>
'''
}
if (!item.severities.empty) {
docCompiled = '''«docCompiled»
Severity of this message as<ul>
'''
}
for (severity : item.severities) {
docCompiled = '''«docCompiled»
<li>«severity»</li>
'''
}
if (!item.severities.empty) {
docCompiled = '''«docCompiled»
</ul>
'''
}
var logger = "" as String
if (withLogger) {
docCompiled = '''«docCompiled»
@param logger set the slf4j logger used when logging this message
'''
parameters += model.toParameter("logger", _typeReferenceBuilder.typeRef(Logger))
logger = "logger,"
} else {
docCompiled = '''«docCompiled»
the default logger «fqMessageClass» will be used
'''
}
var bodyCompiledHasParam=false
var bodyCompiled = '''
return (
new Message(«logger»'''
if (item.logOutput !== null) {
bodyCompiled = '''«bodyCompiled»
"«item.logOutput.escapedFormat»"
, ""
'''
bodyCompiledHasParam=true
}
if (item.showOutput !== null) {
bodyCompiled = '''«bodyCompiled»
«IF bodyCompiledHasParam», «ENDIF»""
, "«item.showOutput.escapedFormat»"
'''
bodyCompiledHasParam=true
}
if (item.allOutput !== null) {
bodyCompiled = '''«bodyCompiled»
«IF bodyCompiledHasParam», «ENDIF»"«item.allOutput.escapedFormat»"
, "«item.allOutput.escapedFormat»"
'''
bodyCompiledHasParam=true
}
for (parameter : item.parameters) {
var typeRef = _typeReferenceBuilder.typeRef(String)
switch (parameter.oftype) {
case BOOLEAN: typeRef = _typeReferenceBuilder.typeRef(typeof(boolean))
case CLASS: typeRef = _typeReferenceBuilder.typeRef(typeof(Class))
case DOUBLE: typeRef = _typeReferenceBuilder.typeRef(typeof(double))
case EXCEPTION: typeRef = _typeReferenceBuilder.typeRef(Exception)
case INTEGER: typeRef = _typeReferenceBuilder.typeRef(typeof(int))
case OBJECT: typeRef = _typeReferenceBuilder.typeRef(typeof(Object))
default: _typeReferenceBuilder.typeRef(String)
}
parameters += model.toParameter(parameter.name, typeRef)
docCompiled = '''«docCompiled»
@param «parameter.name» «parameter.documentation»
'''
bodyCompiled = '''«bodyCompiled»
, "«parameter.name»", «parameter.name»
'''
}
bodyCompiled = '''«bodyCompiled»))
'''
for (severity : item.severities) {
bodyCompiled = '''«bodyCompiled»
.«CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, severity.toString.replace('-', '_'))»()
'''
}
bodyCompiled = '''«bodyCompiled»;'''
if (item.documentation instanceof String) {
docCompiled = '''«docCompiled»
@return instance of Message, which can be used any further
'''
}
static = true
final = true
visibility = JvmVisibility.PUBLIC
documentation = docCompiled.trim
val theBody = bodyCompiled
body = [append('''«theBody»''')]
]
}
def String escapedFormat(MessageText msg) {
return msg.text.replaceAll('''\n''', '''\\n''').replaceAll('''\t''', '''\\t''');
}
}