blob: 554ae6ebeedd7f43f92394734c1592fef20b292a [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 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
*
*
* This copyright notice shows up in the generated Java code
*
*/
package org.eclipse.osbp.xtext.messagedsl.jvmmodel
import org.eclipse.osbp.xtext.messagedsl.MessageCategory
import org.eclipse.osbp.xtext.messagedsl.MessageGroup
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.common.AMessageGroup
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.naming.IQualifiedNameProvider
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
import org.eclipse.osbp.ui.api.metadata.IDSLMetadataService
import org.eclipse.xtext.common.types.JvmType
import java.util.Locale
import org.eclipse.xtext.common.types.JvmGenericType
import org.eclipse.xtext.common.types.JvmField
import javax.annotation.PostConstruct
import javax.inject.Inject
import com.google.common.base.CaseFormat
import org.eclipse.osbp.xtext.messagedsl.MessageDefaultFormat
import org.eclipse.osbp.ui.api.user.IUser
/**
* <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)
superTypes += _typeReferenceBuilder.typeRef(IUser.UserLocaleListener)
// @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.toFields(model)
it.toOperations(model)
category.groups.forEach [ group |
it.addMessageGroup(model, category, group, acceptor)
group.items.forEach [ item |
it.members += toMethod(false, model, category, group, item, acceptor)
it.members += toMethod(true, model, category, group, item, acceptor)
]
]
]
]
}
def toOperations(JvmGenericType type, MessageModel model) {
type.members += model.toMethod("registerLocaleListener", _typeReferenceBuilder.typeRef(Void::TYPE),
[
visibility = JvmVisibility.PROTECTED
annotations += _annotationTypesBuilder.annotationRef(PostConstruct)
body = [append('''user.addUserLocaleListener(this);''')]
])
type.members += model.toMethod("localeChanged", _typeReferenceBuilder.typeRef(Void::TYPE),
[
visibility = JvmVisibility.PUBLIC
annotations += _annotationTypesBuilder.annotationRef(Override)
parameters += model.toParameter("locale", _typeReferenceBuilder.typeRef(Locale))
body = [append('''this.locale = locale;''')]
])
}
def toFields(JvmGenericType type, MessageModel model) {
var JvmField field = null
field = model.toField("dslMetadataService", _typeReferenceBuilder.typeRef(IDSLMetadataService))[
annotations += _annotationTypesBuilder.annotationRef(Inject)]
field.static = true
type.members += field
field = model.toField("user", _typeReferenceBuilder.typeRef(IUser))[
annotations += _annotationTypesBuilder.annotationRef(Inject)]
type.members += field
field = model.toField("locale", _typeReferenceBuilder.typeRef(Locale))
field.static = true
type.members += field
}
/**
* <p>build the inner class UiProvider.</p>
*
*/
def void addMessageGroup(JvmDeclaredType type, MessageModel model, MessageCategory category, MessageGroup group,
IJvmDeclaredTypeAcceptor acceptor) {
var cls = model.toClass(group.name)
type.members += cls
cls.superTypes += _typeReferenceBuilder.typeRef(typeof(AMessageGroup))
cls.static = true
cls.members += model.toConstructor(
[
body = [append('''super(«category.getSimpleMessageClass».class);''')]
])
var field = model.toField('''s«group.name»''', _typeReferenceBuilder.typeRef(AMessageGroup));
type.members += field
field.visibility = JvmVisibility.PRIVATE
field.static = true
field.final = true
field.setInitializer([append('''new «group.name»()''')])
}
/**
* 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.eContainer as MessageCategory).getFQMessageClass
}
/**
* return the generated method name for the message item
*/
public def static String getMethodName(MessageItem item) {
return item.itemName
}
/**
* return the generated item name for the message item, used for i18n
*/
public def static String getItemName(MessageItem item) {
return '''«(item.eContainer as MessageGroup).name»_«item.name»'''
}
def JvmOperation toMethod(boolean withLogger, MessageModel model, MessageCategory category, MessageGroup group,
MessageItem item, IJvmDeclaredTypeAcceptor acceptor) {
return model.toMethod('''«item.itemName»''', _typeReferenceBuilder.typeRef(Message)) [
val fqMessageClass = item.FQMessageClass
val itemName = item.itemName
// val i18nKey = BasicTranslator.getTranslatorKey(messageClass, itemName)
var docCompiled = "" as String
if (group.documentation instanceof String) {
docCompiled = '''«docCompiled»
«group.documentation»<br>
'''
}
if (item.documentation instanceof String) {
docCompiled = '''«docCompiled»
«item.documentation»<br>
'''
}
if (!item.automaticOutputs.empty) {
docCompiled = '''«docCompiled»
Automatic output of this message as<ul>
'''
}
for (automaticOutput : item.automaticOutputs) {
docCompiled = '''«docCompiled»
<li>«automaticOutput»</li>
'''
}
if (!item.automaticOutputs.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 bodyCompiled = '''
return (
new Message(dslMetadataService, locale, «logger»«fqMessageClass».class, s«group.name», "«itemName»"'''
if ((item.logFormat != null) && (item.showFormat != null)) {
bodyCompiled = '''«bodyCompiled»
, "«item.logFormat.escapedFormat»"
, "«item.showFormat.escapedFormat»"
'''
} else {
bodyCompiled = '''«bodyCompiled»
, "«item.allFormat.escapedFormat»"
, "«item.allFormat.escapedFormat»"
'''
}
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 (automaticOutput : item.automaticOutputs) {
bodyCompiled = '''«bodyCompiled»
.«CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, automaticOutput.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(MessageDefaultFormat defaultFormat) {
return defaultFormat.format.replaceAll('''\n''', '''\\n''').replaceAll('''\t''', '''\\t''');
}
}