private ForEachExecution produceNewForEachContext( DelayedReference reference, ForeachProductionResult producedResult) { ForEachExecution newContext = TextblocksFactory.eINSTANCE.createForEachExecution(); newContext.setForeachPedicatePropertyInit( (ForeachPredicatePropertyInit) reference.getQueryElement()); newContext.setSourceModelElement((EObject) reference.getModelElement()); newContext.setContextElement( (EObject) producedResult.getForeachExpressionResultForWhichProduced()); newContext.setTemplateUsedForProduction(producedResult.getTemplateUsedForProduction()); newContext.setResultModelElement((EObject) reference.getRealValue()); return newContext; }
/** * A <code>foreach</code> expression was (re-)evaluated, and for each result, based on any <code> * when</code>/ <code>as</code> {@link com.sap.furcas.metamodel.FURCAS.TCS.PredicateSemantic} * elements, the corresponding template's production rule was executed by the parser. This * produced a {@link ModelElementProxy} which has not yet been turned into a real {@link EObject} * yet nor has it been entered into the target feature. * * <p>Prior executions of the same <code>foreach</code> predicate on the same source model element * may have happened. In this case, there will be {@link ForEachExecution} records documenting * this. If no such records are found, all proxies produced will be materialized as {@link * EObject}s and {@link #setReference(DelayedReference, Object, IModelAdapter, ModelElementProxy, * IModelInjector, int) added/set} to/into the target feature described by the <code>reference * </code>. * * <p>If {@link ForEachExecution} objects are found for the source element and <code>foreach * </code> predicate, their {@link ForEachExecution#getResultModelElement() result elements} are * obtained and compared to the new {@link ForeachProductionResult production instructions} which * also contain the {@link Template} used to produce the target element. The template is used to * compare the element types in order to try to re-use already existing elements. * * <p>In case a target object from a prior evaluation can be re-used, it is set as the proxy's * {@link ModelElementProxy#setRealObject(Object) real object}, and no new target object is * created for this <code>foreach</code> result. Otherwise, a new target object is created. The * re-used or created object is then used to replace (single multiplicity) or to add to * (many-multiplicity) the target feature. * * <p>As to the re-use strategy, we distinguish between re-using the {@link ForEachExecution} hull * only and the {@link ForEachExecution#getResultModelElement() result element} that was produced * in an earlier run. Two element collections are compared, namely those listed as {@link * ForEachExecution#getResultModelElement() result elements} of earlier evaluations on the <code> * reference</code>'s {@link DelayedReference#getTextBlock() text block} for the same <code> * foreach</code> predicate; and those described by <code>producedResults</code> which contains * proxies and the templates telling the types and modes with which they were created. The two * collections are iterated in parallel. If the {@link ForEachExecution}'s template matches that * in the current <code>producedResults</code> element, the {@link * ForEachExecution#getResultModelElement() old result element} is re-used by {@link * ModelElementProxy#setRealObject(Object) setting} it on the proxy. Otherwise, a new element is * produced using {@link ModelInjector#createOrResolve(ModelElementProxy, ANTLR3LocationToken, * ANTLR3LocationToken)} and the existing {@link ForEachExecution} is updated for the new result * element, template, etc. If the collection of {@link ForEachExecution} elements is shorter than * that of the <code>producedResults</code>, additional {@link ForEachExecution} elements are * added to the <code>reference</code>'s {@link TextBlock#getForEachExecutions() textblock's * foreach context list}. Extraneous elements are deleted from it. * * <p>It's obvious that there may be more sophisticated re-use strategies based on longest * sequence etc., but those may be added later. * * @param injector TODO * @param producedResults the {@link ForeachProductionResult#getTemplateUsedForProduction() * templates} need to be set only if text blocks are being produced by the parser run */ private void setReferenceAndUpdateForeachContexts( DelayedReference reference, IModelAdapter modelAdapter, IModelInjector injector, List<ForeachProductionResult> producedResults) throws ModelElementCreationException, ModelAdapterException { Iterator<ForEachExecution> foreachContextIterator = null; ForEachExecution nextOldForeachContext = null; if (reference.getTextBlock() != null) { foreachContextIterator = ((TextBlock) reference.getTextBlock()).getForEachExecutions().iterator(); nextOldForeachContext = getNextForeachContext(foreachContextIterator, reference); } int i = 0; for (ForeachProductionResult producedResult : producedResults) { // check for a re-usable target element of ForEachContext with its result element if (nextOldForeachContext != null && isTargetElementReusable(nextOldForeachContext, producedResult)) { // re-use the target object referenced by the ForEachContext and the ForEachContext itself producedResult .getProducedProxy() .setRealObject(nextOldForeachContext.getResultModelElement()); if (producedResult.getForeachExpressionResultForWhichProduced() instanceof EObject) { nextOldForeachContext.setContextElement( (EObject) producedResult.getForeachExpressionResultForWhichProduced()); } else if (producedResult.getForeachExpressionResultForWhichProduced() instanceof EObject) { nextOldForeachContext.setContextString( (String) producedResult.getForeachExpressionResultForWhichProduced()); } reference.setRealValue(nextOldForeachContext.getResultModelElement()); } else { // target element is not re-usable, a new one needs to be produced setReference( reference, producedResult.getForeachExpressionResultForWhichProduced(), modelAdapter, producedResult.getProducedProxy(), injector, i); if (reference.getTextBlock() != null && producedResult.getTemplateUsedForProduction() != null) { // if we have a ForEachContext element for the current source element and foreach // predicate, // re-use and update it: if (nextOldForeachContext == null) { // no ForEachContext element; produce a new one and append ForEachExecution newContext = produceNewForEachContext(reference, producedResult); ((TextBlock) reference.getTextBlock()).getForEachExecutions().add(newContext); } else { // ForEachContext names a template/element that can't be re-used; update it // correspondingly Object result = producedResult.getForeachExpressionResultForWhichProduced(); if (result instanceof EObject) { nextOldForeachContext.setContextElement( (EObject) producedResult.getForeachExpressionResultForWhichProduced()); } else if (result instanceof String) { nextOldForeachContext.setContextString( (String) producedResult.getForeachExpressionResultForWhichProduced()); } nextOldForeachContext.setTemplateUsedForProduction( producedResult.getTemplateUsedForProduction()); nextOldForeachContext.setResultModelElement( (EObject) producedResult.getProducedProxy().getRealObject()); } } } if (nextOldForeachContext != null && foreachContextIterator != null && foreachContextIterator.hasNext()) { nextOldForeachContext = foreachContextIterator.next(); } else { nextOldForeachContext = null; } i++; } // delete remaining old ForEachContext entries from reference's textblock while (nextOldForeachContext != null) { foreachContextIterator.remove(); nextOldForeachContext = getNextForeachContext(foreachContextIterator, reference); } }