blob: f232d0fb5871cb3105a3050011eb14a185b4aebb [file] [log] [blame]
/**
* Copyright (c) 2011, 2015 - Lunifera GmbH (Gross Enzersdorf, Austria), 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:
* Florian Pirchner - Initial implementation
*/
package org.eclipse.osbp.dsl.entity.xtext.extensions
import com.google.inject.Inject
import java.util.ArrayList
import javax.persistence.PreRemove
import org.eclipse.osbp.dsl.common.xtext.extensions.TreeAppendableExtensions
import org.eclipse.osbp.dsl.common.xtext.jvmmodel.CommonTypesBuilder
import org.eclipse.osbp.dsl.entity.xtext.jvmmodel.AnnotationCompiler
import org.eclipse.osbp.dsl.entity.xtext.linker.EntityLinker
import org.eclipse.osbp.dsl.semantic.common.types.LClass
import org.eclipse.osbp.dsl.semantic.common.types.LFeature
import org.eclipse.osbp.dsl.semantic.common.types.LPackage
import org.eclipse.osbp.dsl.semantic.common.types.LType
import org.eclipse.osbp.dsl.semantic.entity.LBean
import org.eclipse.osbp.dsl.semantic.entity.LBeanFeature
import org.eclipse.osbp.dsl.semantic.entity.LBeanReference
import org.eclipse.osbp.dsl.semantic.entity.LEntity
import org.eclipse.osbp.dsl.semantic.entity.LEntityFeature
import org.eclipse.osbp.dsl.semantic.entity.LEntityReference
import org.eclipse.osbp.dsl.semantic.entity.LOperation
import org.eclipse.xtext.common.types.JvmField
import org.eclipse.xtext.common.types.JvmOperation
import org.eclipse.xtext.common.types.JvmTypeReference
import org.eclipse.xtext.common.types.JvmVisibility
import org.eclipse.xtext.common.types.TypesFactory
import org.eclipse.xtext.common.types.util.TypeReferences
import org.eclipse.xtext.util.EcoreGenericsUtil
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1
import org.eclipse.osbp.runtime.common.historized.UUIDHist
import org.eclipse.osbp.dsl.semantic.entity.LEntityAttribute
import org.eclipse.osbp.dsl.semantic.common.types.LReference
import org.eclipse.osbp.dsl.semantic.common.types.LStateClass
class EntityTypesBuilder extends CommonTypesBuilder {
@Inject extension ModelExtensions
@Inject extension NamingExtensions
@Inject extension TreeAppendableExtensions
@Inject AnnotationCompiler annotationCompiler
@Inject TypesFactory typesFactory;
@Inject TypeReferences references;
@Inject EcoreGenericsUtil ecoreGenericsUtil;
@Inject EntityLinker linker;
def htmlCode(CharSequence s) {
"<code>".concat(String::valueOf(s)).concat("</code>")
}
def dispatch JvmOperation toDispose(LEntity lClass) {
val op = typesFactory.createJvmOperation();
op.visibility = JvmVisibility::PUBLIC
op.returnType = references.getTypeForName(Void::TYPE, lClass)
op.simpleName = "dispose"
annotationCompiler.addDisposeFieldAnnotation(lClass, op)
op.documentation = '''
Calling dispose will destroy that instance. The internal state will be
set to 'disposed' and methods of that object must not be used anymore.
Each call will result in runtime exceptions.<br>
If this object keeps composition containments, these will be disposed too.
So the whole composition containment tree will be disposed on calling this method.'''
setBody(op, [ // ITreeAppendable
if(it == null) return
val p = it.trace(lClass)
p >> '''
if (isDisposed()) {
return;
}
'''
val compositionContainmentProps = lClass.features.filter[it|it instanceof LEntityReference && (it as LEntityReference).cascading]
if (!compositionContainmentProps.empty) {
p >> "try " >>> "{"
p >> "// Dispose all the composition references.\n"
for (prop : compositionContainmentProps) {
val fieldRef = "this.".concat(prop.toName.toFirstLower)
val typeName = prop.typeName
val typeVar = typeName.toFirstLower
if (prop.toMany) {
p >> '''
if («fieldRef» != null) {
for («typeName» «typeVar» : «fieldRef») {
«typeVar».dispose();
}
«fieldRef» = null;
}
'''
} else {
p >> '''
if («fieldRef» != null) {
«fieldRef».dispose();
«fieldRef» = null;
}
'''
}
}
p <<< "}"
p >>> "finally {"
// p.increaseIndentation
}
if (lClass.superType != null) {
p >> "super.dispose();"
} else {
p >> "disposed = true;"
}
if (!compositionContainmentProps.empty) {
p <<< "}"
}
])
associate(lClass, op)
}
def dispatch JvmOperation toDispose(LBean lClass) {
val op = typesFactory.createJvmOperation();
op.visibility = JvmVisibility::PUBLIC
op.returnType = references.getTypeForName(Void::TYPE, lClass)
op.simpleName = "dispose"
annotationCompiler.addDisposeFieldAnnotation(lClass, op)
op.documentation = '''
Calling dispose will destroy that instance. The internal state will be
set to 'disposed' and methods of that object must not be used anymore.
Each call will result in runtime exceptions.<br>
If this object keeps composition containments, these will be disposed too.
So the whole composition containment tree will be disposed on calling this method.'''
setBody(op, [ // ITreeAppendable
if(it == null) return
val p = it.trace(lClass)
p >> '''
if (isDisposed()) {
return;
}
'''
val compositionContainmentProps = lClass.features.filter[it|it instanceof LEntityReference && (it as LEntityReference).cascading]
if (!compositionContainmentProps.empty) {
p >> "try " >>> "{"
p >> "// Dispose all the composition references.\n"
for (prop : compositionContainmentProps) {
val fieldRef = "this.".concat(prop.toName.toFirstLower)
val typeName = prop.typeName
val typeVar = typeName.toFirstLower
if (prop.toMany) {
p >> '''
if («fieldRef» != null) {
for («typeName» «typeVar» : «fieldRef») {
«typeVar».dispose();
}
«fieldRef» = null;
}
'''
} else {
p >> '''
if («fieldRef» != null) {
«fieldRef».dispose();
«fieldRef» = null;
}
'''
}
}
p <<< "}"
p >>> "finally {"
// p.increaseIndentation
}
if (lClass.superType != null) {
p >> "super.dispose();"
} else {
p >> "disposed = true;"
}
if (!compositionContainmentProps.empty) {
p <<< "}"
}
])
associate(lClass, op)
}
def JvmField toField(LStateClass stateClass) {
val JvmField jvmField = typesFactory.createJvmField();
jvmField.simpleName = stateClass.toName.toFirstLower
jvmField.visibility = JvmVisibility::PRIVATE
jvmField.type = cloneWithProxies(stateClass.toTypeReferenceWithMultiplicity)
jvmField.documentation = stateClass.getDocumentation
annotationCompiler.processAnnotation(stateClass, jvmField);
associate(stateClass, jvmField);
}
override JvmField toField(LFeature prop) {
prop.internalToField
}
def dispatch JvmField internalToField(LBeanFeature prop) {
val JvmField jvmField = typesFactory.createJvmField();
jvmField.simpleName = prop.toName
jvmField.visibility = JvmVisibility::PRIVATE
jvmField.type = cloneWithProxies(prop.toTypeReferenceWithMultiplicity)
jvmField.documentation = prop.getDocumentation
annotationCompiler.processAnnotation(prop, jvmField);
associate(prop, jvmField);
}
def dispatch JvmField internalToField(LBeanReference prop) {
val JvmField jvmField = typesFactory.createJvmField();
jvmField.simpleName = prop.toName
jvmField.visibility = JvmVisibility::PRIVATE
jvmField.type = prop.toTypeReferenceWithMultiplicity
jvmField.documentation = prop.getDocumentation
annotationCompiler.processAnnotation(prop, jvmField);
associate(prop, jvmField);
}
def dispatch JvmField internalToField(LEntityAttribute prop) {
val LEntity entity = prop.entity
val JvmField jvmField = typesFactory.createJvmField();
jvmField.simpleName = prop.toName
jvmField.visibility = JvmVisibility::PRIVATE
jvmField.type = cloneWithProxies(prop.toTypeReferenceWithMultiplicity)
jvmField.documentation = prop.getDocumentation
// if uuid or historized entity AND a uuid property is present too
if (prop.isUUID && !(entity.timedependent || entity.historized)) {
jvmField.setInitializer [
if(it === null) return
val p = it.trace(prop)
p >> '''java.util.UUID.randomUUID().toString()'''
]
} else if (prop.isID && (entity.timedependent || entity.historized)) {
jvmField.setInitializer [
if(it === null) return
val p = it.trace(prop)
p >> '''new UUIDHist()'''
]
}
annotationCompiler.processAnnotation(prop, jvmField);
associate(prop, jvmField);
}
def dispatch JvmField internalToField(LEntityReference prop) {
val LEntity entity = prop.entity
val JvmField jvmField = typesFactory.createJvmField();
jvmField.simpleName = prop.toName
jvmField.visibility = JvmVisibility::PRIVATE
jvmField.type = prop.toTypeReferenceWithMultiplicity
jvmField.documentation = prop.getDocumentation
// if uuid or historized entity AND a uuid property is present too
if (prop.isUUID || ((entity.timedependent || entity.historized) &&
entity.uuidPresent)) {
jvmField.setInitializer [
if(it == null) return
val p = it.trace(prop)
p >> '''java.util.UUID.randomUUID().toString()'''
]
}
annotationCompiler.processAnnotation(prop, jvmField);
associate(prop, jvmField);
}
def boolean uuidPresent(LEntity entity) {
entity.allAttributes.exists[it.uuid]
}
def JvmOperation toMethod(LOperation sourceElement, String name, JvmTypeReference returnType,
Procedure1<? super JvmOperation> initializer) {
val op = typesFactory.createJvmOperation()
op.simpleName = name
op.visibility = JvmVisibility::PUBLIC
op.returnType = cloneWithProxies(returnType)
annotationCompiler.processAnnotation(sourceElement, op);
associate(sourceElement, op);
initializeSafely(op, initializer);
}
def JvmOperation toSetter(LEntityFeature prop) {
if (prop.toMany) {
throw new RuntimeException("toMany-References not allowed for setters!");
}
val paramName = prop.toMethodParamName
val typeRef = prop.toTypeReference
val opposite = if(prop instanceof LEntityReference) (prop as LEntityReference).resolvedOpposite else null
val op = typesFactory.createJvmOperation();
op.visibility = JvmVisibility::PUBLIC
op.returnType = references.getTypeForName(Void::TYPE, prop)
op.simpleName = prop.toSetterName
op.parameters += prop.toParameter(paramName, typeRef)
op.documentation = "Sets the " + paramName + " property to this instance." + if (opposite != null) {
"\nSince the reference is a container reference, the opposite reference " + "(" + prop.typeName + "." +
opposite.name.toFirstLower + ")\n" + "of the " + paramName +
" will be handled automatically and no further coding is required to keep them in sync.\n" +
"See {@link " + prop.typeName + "#" + opposite.toSetterName + "(" + prop.typeName + ")}."
} else
""
setBody(op, [ // ITreeAppendable
if(it == null) return
val p = it.trace(prop);
p >> prop.toCheckDisposedCall()
val fieldRef = "this." + prop.toName
if (opposite == null) {
p >> fieldRef + " = " + paramName + ";"
} else {
p >> "if (" + fieldRef + " != null) " >>> "{"
if (opposite.toMany) {
p >> fieldRef + "." + opposite.toCollectionInternalRemoverName + "(this);"
} else {
p >> fieldRef + "." + opposite.toInternalSetterName + "(null);"
}
p <<< "}"
// p >> fieldRef + " = " + paramName + ";\n"
p >> "internalSet" + prop.toName.toFirstUpper + "(" + paramName + ");\n"
p >> "if (" + fieldRef + " != null) " >>> "{"
if (opposite.toMany) {
p >> fieldRef + "." + opposite.toCollectionInternalAdderName + "(this);"
} else {
p >> fieldRef + "." + opposite.toInternalSetterName + "(this);"
}
p <<< "}"
}
])
return associate(prop, op);
}
def JvmOperation toSetter(LStateClass prop) {
val paramName = prop.name.toFirstLower
val typeRef = prop.toTypeReference
val op = typesFactory.createJvmOperation();
op.visibility = JvmVisibility::PUBLIC
op.returnType = references.getTypeForName(Void::TYPE, prop)
op.simpleName = prop.toSetterName
op.parameters += prop.toParameter(paramName, typeRef)
op.documentation = "Sets the " + paramName + " property to this instance."
setBody(op, [ // ITreeAppendable
if(it == null) return
val p = it.trace(prop);
p >> prop.toCheckDisposedCall()
val fieldRef = "this." + prop.toName.toFirstLower
p >> fieldRef + " = " + paramName + ";"
])
return associate(prop, op);
}
def JvmOperation toSetter(LBeanFeature prop) {
if (prop.toMany) {
throw new RuntimeException("toMany-References not allowed for setters!");
}
val paramName = prop.toMethodParamName
val typeRef = prop.toTypeReference
val opposite = if(prop instanceof LBeanReference) (prop as LBeanReference).resolvedOpposite else null
val op = typesFactory.createJvmOperation();
op.visibility = JvmVisibility::PUBLIC
op.returnType = references.getTypeForName(Void::TYPE, prop)
op.simpleName = prop.toSetterName
op.parameters += prop.toParameter(paramName, typeRef)
op.documentation = "Sets the " + paramName + " property to this instance." + if (opposite != null) {
"\nSince the reference is a container reference, the opposite reference " + "(" + prop.typeName + "." +
opposite.name.toFirstLower + ")\n" + "of the " + paramName +
" will be handled automatically and no further coding is required to keep them in sync.\n" +
"See {@link " + prop.typeName + "#" + opposite.toSetterName + "(" + prop.typeName + ")}."
} else
""
setBody(op, [ // ITreeAppendable
if(it == null) return
val p = it.trace(prop);
p >> prop.toCheckDisposedCall()
val fieldRef = "this." + prop.toName
if (opposite == null) {
p >> fieldRef + " = " + paramName + ";"
} else {
p >> "if (" + fieldRef + " != null) " >>> "{"
if (opposite.toMany) {
p >> fieldRef + "." + opposite.toCollectionInternalRemoverName + "(this);"
} else {
p >> fieldRef + "." + opposite.toInternalSetterName + "(null);"
}
p <<< "}"
p >> fieldRef + " = " + paramName + ";\n"
p >> "if (" + fieldRef + " != null) " >>> "{"
if (opposite.toMany) {
p >> fieldRef + "." + opposite.toCollectionInternalAdderName + "(this);"
} else {
p >> fieldRef + "." + opposite.toInternalSetterName + "(this);"
}
p <<< "}"
// if (this.«fieldName» != null) {
// «IF ref.opposite.toMany»
// this.«fieldName».«ref.opposite.toCollectionInternalRemoverName»(this);
// «ELSE»
// this.«fieldName».«ref.opposite.toInternalSetterName»(null);
// «ENDIF»
// }
// this.«fieldName» = «localVarName»;
// if (this.«fieldName» != null) {
// «IF ref.opposite.toMany»
// this.«fieldName».«ref.opposite.toCollectionInternalAdderName»(this);
// «ELSE»
// this.«fieldName».«ref.opposite.toInternalSetterName»(this);
// «ENDIF»
// }
}
])
return associate(prop, op);
}
/**
* Builds an adder method for a *toMany relation like
* <code>Order.addToOrderLines(OrderLine orderLine)</code>.
*/
def dispatch JvmOperation toAdder(LEntityFeature prop, String propertyName) {
val paramName = prop.typeName.toFirstLower
val JvmOperation op = typesFactory.createJvmOperation();
op.visibility = JvmVisibility::PUBLIC
op.returnType = references.getTypeForName(Void::TYPE, prop)
op.simpleName = prop.toCollectionAdderName
if (prop.toTypeReference != null) {
op.parameters += prop.toParameter(paramName, prop.toTypeReference)
}
op.documentation = '''
Adds the given «paramName» to this object. <p>
«IF prop.opposite != null»
Since the reference is a composition reference, the opposite reference («prop.typeName».«prop.opposite.name.
toFirstLower»)
of the «paramName» will be handled automatically and no further coding is required to keep them in sync.
See {@link «prop.typeName»#«prop.opposite.toSetterName»(«prop.typeName»)}.
«ELSE»
ATTENTION:<br>
The reference is a composition reference, but no opposite is available.
So the opposite will NOT be handled. Therefore you have to ensure that the parent of the reference
is set properly.
«ENDIF»'''
setBody(op, [ // ITreeAppendable
if(it == null) return
val p = it.trace(prop);
p += prop.toCheckDisposedCall()
if (prop.opposite != null) {
p >> paramName + "." + prop.opposite.toSetterName + "(this);"
} else {
p >> "if (!" + prop.toCollectionInternalGetterName + "().contains(" + paramName + "))" >>> "{"
{
p >> prop.toCollectionInternalAdderName + "(" + paramName + ");"
}
p <<< "}"
}
])
return associate(prop, op);
}
/**
* Builds an adder method for a *toMany relation like
* <code>Order.addToOrderLines(OrderLine orderLine)</code>.
*/
def dispatch JvmOperation toAdder(LBeanFeature prop, String propertyName) {
val paramName = prop.typeName.toFirstLower
val JvmOperation op = typesFactory.createJvmOperation();
op.visibility = JvmVisibility::PUBLIC
op.returnType = references.getTypeForName(Void::TYPE, prop)
op.simpleName = prop.toCollectionAdderName
if (prop.toTypeReference != null) {
op.parameters += prop.toParameter(paramName, prop.toTypeReference)
}
op.documentation = '''
Adds the given «paramName» to this object. <p>
«IF prop.opposite != null»
Since the reference is a composition reference, the opposite reference («prop.typeName».«prop.opposite.name.
toFirstLower»)
of the «paramName» will be handled automatically and no further coding is required to keep them in sync.
See {@link «prop.typeName»#«prop.opposite.toSetterName»(«prop.typeName»)}.
«ELSEIF !(prop.type instanceof LBean)»
ATTENTION:<br>
The reference is a composition reference, but no opposite is available.
So the opposite will NOT be handled. Therefore you have to ensure that the parent of the reference
is set properly.
«ENDIF»'''
setBody(op, [ // ITreeAppendable
if(it == null) return
val p = it.trace(prop);
p += prop.toCheckDisposedCall()
if (prop.opposite != null) {
p >> paramName + "." + prop.opposite.toSetterName + "(this);"
} else {
p >> "if (!" + prop.toGetterName + "().contains(" + paramName + "))" >>> "{"
{
p >> prop.toCollectionInternalAdderName + "(" + paramName + ");"
}
p <<< "}"
}
])
return associate(prop, op);
}
/**
* Builds a setter method for a *toMany relation like
* <code>Order.setOrderLines(List&lt;OrderLine&gt; orderLines)</code>.
*/
def JvmOperation toCollectionSetter(LFeature prop, String propertyName) {
val paramName = prop.typeName.toFirstLower
val JvmOperation op = typesFactory.createJvmOperation();
op.visibility = JvmVisibility::PUBLIC
op.returnType = references.getTypeForName(Void::TYPE, prop)
op.simpleName = prop.toSetterName
if (prop.toTypeReference != null) {
op.parameters += prop.toParameter(propertyName, prop.toTypeReferenceWithMultiplicity)
}
op.documentation = '''
Sets the given «propertyName» to the object. Currently contained «propertyName» instances will be removed.
@param «propertyName» the list of new instances'''
op.body = '''
// remove the old «paramName»
for(«prop.typeName» oldElement : new ArrayList<«prop.typeName»>(this.«prop.toCollectionInternalGetterName»())){
«prop.toCollectionRemoverName»(oldElement);
}
// add the new «paramName»
for(«prop.typeName» newElement : «propertyName»){
«prop.toCollectionAdderName»(newElement);
}
'''
return associate(prop, op);
}
// /**
// * A getter to return the historized compound key.
// */
// def JvmOperation toGetHistCompoundKey(LType type, String idProp, String validFromProp) {
// val JvmOperation op = typesFactory.createJvmOperation();
// op.visibility = JvmVisibility::PUBLIC
// op.returnType = references.getTypeForName(typeof(UUIDHist), type)
// op.simpleName = "getHistCompoundKey"
//
// op.documentation = '''
// Returns the compound id for historized objects'''
// op.body = '''
// return new HistCompoundId(«idProp», «validFromProp»);
// '''
// return associate(type, op);
// }
/**
* Builds a setter method for a *toMany relation like
* <code>Order.setOrderLines(List&lt;OrderLine&gt; orderLines)</code>.
*/
def JvmOperation toPreRemove(LEntity entity) {
val JvmOperation op = typesFactory.createJvmOperation();
op.visibility = JvmVisibility::PROTECTED
op.returnType = references.getTypeForName(Void::TYPE, entity)
op.simpleName = "preRemove"
op.documentation = '''Iterates all cross references and removes them from the parent to avoid ConstraintViolationException'''
op.annotations += entity.toAnnotation(typeof(PreRemove))
op.body = '''
«FOR ref : entity.references»
«IF !ref.cascading && ref.opposite != null && ref.bounds.toMany»
// remove the «ref.name»
for(«ref.typeName» oldElement : new ArrayList<«ref.typeName»>(this.«ref.toCollectionInternalGetterName»())){
«ref.toCollectionRemoverName»(oldElement);
}
«ENDIF»
«ENDFOR»
'''
return associate(entity, op);
}
def JvmVisibility getInternalMethodVisibility(LFeature ref) {
val LPackage ownerPackage = (ref.eContainer() as LType).package;
val LPackage refPackage = ref.type.package;
if (ownerPackage.equals(refPackage)) {
null // package visibility
} else {
JvmVisibility::PUBLIC
}
}
override JvmOperation toIsDisposed(LClass lClass) {
val op = super.toIsDisposed(lClass)
annotationCompiler.addDisposeFieldAnnotation(lClass, op)
return op
}
def JvmField toDiposeField(LType sourceElement) {
val JvmField field = sourceElement.toPrimitiveTypeField("disposed", Boolean::TYPE)
associate(sourceElement, field)
annotationCompiler.addDisposeFieldAnnotation(sourceElement, field)
return field
}
def JvmOperation toInternalSetter(LFeature prop) {
val paramName = prop.toMethodParamName
val typeRef = prop.toTypeReference
val JvmOperation result = typesFactory.createJvmOperation();
result.visibility = JvmVisibility::PUBLIC
result.returnType = references.getTypeForName(Void::TYPE, prop)
result.simpleName = prop.toInternalSetterName
result.parameters += prop.toParameter(paramName, typeRef)
result.documentation = '''For internal use only!'''
setBody(result, [ // ITreeAppendable
if(it == null) return
val p = it.trace(prop)
p >> "this." + prop.toName + " = " + paramName + ";"
])
return associate(prop, result);
}
def JvmOperation toInternalAdder(LFeature prop) {
val paramName = prop.typeName.toFirstLower
val typeRef = prop.toTypeReference
val JvmOperation op = typesFactory.createJvmOperation();
op.visibility = JvmVisibility::PUBLIC
op.returnType = references.getTypeForName(Void::TYPE, prop)
op.simpleName = prop.toCollectionInternalAdderName
val param = prop.toParameter(paramName, typeRef);
if (param != null) {
op.parameters += param
}
op.documentation = '''For internal use only!'''
op.body = '''
if(«paramName» == null) {
return;
}
««« if(!«prop.toCollectionInternalGetterName»().contains(«paramName»)) {
«prop.toCollectionInternalGetterName»().add(«paramName»);
««« }
'''
return associate(prop, op);
}
def JvmOperation toInternalRemover(LFeature prop) {
val paramName = prop.typeName.toFirstLower
val typeRef = prop.toTypeReference
val op = typesFactory.createJvmOperation();
op.visibility = JvmVisibility::PUBLIC
op.returnType = references.getTypeForName(Void::TYPE, prop)
op.simpleName = prop.toCollectionInternalRemoverName
val param = prop.toParameter(paramName, typeRef);
if (param != null) {
op.parameters += param
}
op.documentation = '''For internal use only!'''
setBody(op, [ // ITreeAppendable
if(it == null) return
val p = it.trace(prop)
p >> prop.toCollectionInternalGetterName + "()" + ".remove(" + paramName + ");"
])
return associate(prop, op)
}
def JvmOperation toInternalCollectionGetter(LFeature prop, String name) {
val fieldName = name.toFirstLower
val JvmOperation op = typesFactory.createJvmOperation()
op.visibility = JvmVisibility::PUBLIC
op.returnType = prop.toTypeReferenceWithMultiplicity
op.simpleName = prop.toCollectionInternalGetterName
op.documentation = "For internal use only! Returns the list of " + htmlCode(prop.typeName) +
"s thereby lazy initializing it."
setBody(op, [ // ITreeAppendable
if(it == null) return;
var p = it.trace(prop);
val fieldRef = "this." + fieldName
p >> "if (" + fieldRef + " == null)" >>> " {"
{
p >> fieldRef >> " = new " >> newTypeRef(prop, typeof(ArrayList), prop.toTypeReference) >> "();"
}
p <<< "}"
p >> "return " + fieldRef + ";"
])
prop.associate(op)
}
/**
* Builds a remover method for a *toMany relation like
* <code>Order.removeFromOrderLines(OrderLine orderLine)</code>.
*/
def JvmOperation toRemover(LFeature prop, String propertyName) {
val paramName = prop.typeName.toFirstLower
val JvmOperation op = typesFactory.createJvmOperation();
op.visibility = JvmVisibility::PUBLIC
op.returnType = references.getTypeForName(Void::TYPE, prop)
op.simpleName = prop.toCollectionRemoverName
if (prop.toTypeReference != null) {
op.parameters += prop.toParameter(paramName, prop.toTypeReference)
}
if (prop.opposite != null) {
op.documentation = '''
Removes the given «paramName» from this object. <p>
«IF prop instanceof LEntityReference && (prop as LEntityReference).cascading»
Since the reference is a cascading reference, the opposite reference («prop.typeName».«prop.opposite.name.
toFirstLower»)
of the «paramName» will be handled automatically and no further coding is required to keep them in sync.
See {@link «prop.typeName»#«prop.opposite.toSetterName»(«prop.typeName»)}.
«ENDIF»'''
}
setBody(op, [ // ITreeAppendable
if(it == null) return
val p = it.trace(prop);
p += prop.toCheckDisposedCall()
if (prop.opposite != null) {
p >> paramName + "." + prop.opposite.toSetterName + "(null);"
} else {
p >> prop.toCollectionInternalGetterName + "().remove(" + paramName + ");"
}
])
return associate(prop, op);
}
// def EObject createOSBPJvmProxy(EObject obj, EReference eRef, EReference eJvmRef,
// SemanticLoadingResource resource) {
// if (resource == null)
// throw new IllegalStateException("object must be contained in a resource");
// val InternalEObject target = (obj as InternalEObject).eGet(eRef, false, false) as InternalEObject;
// val URI jvmTypeURI = resource.getJvmTypeURI(target.eProxyURI)
// val JvmParameterizedTypeReference typeRef = TypesFactory.eINSTANCE.createJvmParameterizedTypeReference();
// val JvmType proxy = TypesFactory.eINSTANCE.createJvmGenericType();
// typeRef.setType(proxy);
// (proxy as InternalEObject).eSetProxyURI(jvmTypeURI);
// return typeRef;
// }
}