/*
* Copyright 2003-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jetbrains.mps.generator.impl.interpreted;
import jetbrains.mps.generator.impl.GenerationFailureException;
import jetbrains.mps.generator.impl.RuleUtil;
import jetbrains.mps.generator.impl.TemplateQueryException;
import jetbrains.mps.generator.impl.query.MapConfigurationCondition;
import jetbrains.mps.generator.impl.query.QueryKey;
import jetbrains.mps.generator.impl.query.QueryKeyImpl;
import jetbrains.mps.generator.impl.query.QueryProviderBase;
import jetbrains.mps.generator.runtime.TemplateCreateRootRule;
import jetbrains.mps.generator.runtime.TemplateDropAttributeRule;
import jetbrains.mps.generator.runtime.TemplateDropRootRule;
import jetbrains.mps.generator.runtime.TemplateMappingConfiguration;
import jetbrains.mps.generator.runtime.TemplateMappingScript;
import jetbrains.mps.generator.runtime.TemplateModel;
import jetbrains.mps.generator.runtime.TemplateReductionRule;
import jetbrains.mps.generator.runtime.TemplateRootMappingRule;
import jetbrains.mps.generator.runtime.TemplateWeavingRule;
import jetbrains.mps.generator.template.ITemplateGenerator;
import jetbrains.mps.generator.template.TemplateQueryContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.language.SConcept;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.model.SNodeReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Evgeny Gryaznov, Nov 29, 2010
*/
public class TemplateMappingConfigurationInterpreted implements TemplateMappingConfiguration {
private final SNode myMappingConfiguration;
private final TemplateModel myModel;
private List<TemplateReductionRule> myReductionRules;
private List<TemplateCreateRootRule> myCreateRootRules;
private List<TemplateRootMappingRule> myRootMappingRules;
private List<TemplateWeavingRule> myWeavingRules;
private List<TemplateDropRootRule> myDropRootRules;
private List<TemplateMappingScript> myPreScripts;
private List<TemplateMappingScript> myPostScripts;
private List<TemplateDropAttributeRule> myDropAttributeRules;
private MapConfigurationCondition myCondition;
private volatile boolean myInitialized = false;
public TemplateMappingConfigurationInterpreted(TemplateModel model, SNode mappingConfiguration) {
myModel = model;
myMappingConfiguration = mappingConfiguration;
}
private void init() {
if (myInitialized) {
return;
}
synchronized (this) {
myCreateRootRules = new ArrayList<TemplateCreateRootRule>(5);
myRootMappingRules = new ArrayList<TemplateRootMappingRule>(5);
myWeavingRules = new ArrayList<TemplateWeavingRule>(5);
myDropRootRules = new ArrayList<TemplateDropRootRule>(5);
myDropAttributeRules = new ArrayList<TemplateDropAttributeRule>(5);
myPreScripts = new ArrayList<TemplateMappingScript>(5);
myPostScripts = new ArrayList<TemplateMappingScript>(5);
ArrayList<TemplateReductionRule> reductionRules = new ArrayList<TemplateReductionRule>(20);
ArrayList<TemplateReductionRule> patternRules = new ArrayList<TemplateReductionRule>(5);
for (SNode child : myMappingConfiguration.getChildren()) {
final SConcept childConcept = child.getConcept();
if (RuleUtil.concept_Reduction_MappingRule.equals(childConcept)) {
reductionRules.add(new TemplateReductionRuleInterpreted(child));
} else if (RuleUtil.concept_Root_MappingRule.equals(childConcept)) {
myRootMappingRules.add(new TemplateRootMappingRuleInterpreted(child));
} else if (RuleUtil.concept_PatternReduction_MappingRule.equals(childConcept)) {
patternRules.add(new TemplateReductionPatternRuleInterpreted(child));
} else if (RuleUtil.concept_CreateRootRule.equals(childConcept)) {
myCreateRootRules.add(new TemplateCreateRootRuleInterpreted(child));
} else if (RuleUtil.concept_Weaving_MappingRule.equals(childConcept)) {
myWeavingRules.add(new TemplateWeavingRuleInterpreted(child));
} else if (RuleUtil.concept_DropRootRule.equals(childConcept)) {
myDropRootRules.add(new TemplateDropRuleInterpreted(child));
} else if (RuleUtil.concept_MappingScriptReference.equals(childConcept)) {
SNode mappingScript = RuleUtil.getMappingScriptReference_Script(child);
if (mappingScript == null) {
continue;
}
if (RuleUtil.link_MappingConfiguration_preMappingScript.equals(child.getContainmentLink())) {
myPreScripts.add(new TemplateMappingScriptInterpreted(mappingScript));
} else {
myPostScripts.add(new TemplateMappingScriptInterpreted(mappingScript));
}
} else if (RuleUtil.concept_DropAttributeRule.equals(childConcept)) {
myDropAttributeRules.add(new DropAttributeRuleInterpreted(child));
}
}
if (patternRules.isEmpty()) {
myReductionRules = reductionRules;
} else {
myReductionRules = new ArrayList<TemplateReductionRule>(patternRules.size() + reductionRules.size());
myReductionRules.addAll(patternRules);
myReductionRules.addAll(reductionRules);
}
myInitialized = true;
}
}
@Override
public boolean isTopPriority() {
return RuleUtil.getMappingConfiguration_TopPrio(myMappingConfiguration);
}
@Override
public SNodeReference getMappingNode() {
return myMappingConfiguration.getReference();
}
@Override
public boolean isApplicable(ITemplateGenerator generator) throws GenerationFailureException {
try {
if (myCondition == null) {
SNode condition = RuleUtil.getMappingConfiguration_IsApplicable(myMappingConfiguration);
if (condition != null) {
QueryKey identity = new QueryKeyImpl(getMappingNode(), condition.getNodeId(), myMappingConfiguration);
myCondition = generator.getQueryProvider(getMappingNode()).getMapConfigurationCondition(identity);
} else {
myCondition = new QueryProviderBase.Defaults();
}
}
return myCondition.check(new TemplateQueryContext(getMappingNode(), generator));
} catch (GenerationFailureException ex) {
throw ex;
} catch(Throwable th) {
// FIXME technically, this catch shall be inside DefaultQueryExecutionContext, where all such catch are kept. But there's no corresponding method in DQEC
TemplateQueryException ex = new TemplateQueryException("error executing map config condition", th);
ex.setTemplateModelLocation(getMappingNode());
throw ex;
}
}
@Override
public String getName() {
return myMappingConfiguration.getName();
}
@Override
public Collection<TemplateRootMappingRule> getRootRules() {
init();
return myRootMappingRules;
}
@Override
public Collection<TemplateCreateRootRule> getCreateRules() {
init();
return myCreateRootRules;
}
@Override
public Collection<TemplateDropRootRule> getDropRules() {
init();
return myDropRootRules;
}
@Override
public Collection<TemplateReductionRule> getReductionRules() {
init();
return myReductionRules;
}
@Override
public Collection<TemplateWeavingRule> getWeavingRules() {
init();
return myWeavingRules;
}
@Override
public Collection<TemplateMappingScript> getPreScripts() {
init();
return myPreScripts;
}
@Override
public Collection<TemplateMappingScript> getPostScripts() {
init();
return myPostScripts;
}
@NotNull
@Override
public Collection<TemplateDropAttributeRule> getDropAttributeRules() {
init();
return myDropAttributeRules;
}
@Override
public TemplateModel getModel() {
return myModel;
}
}