/* * Copyright 2003-2011 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.smodel.runtime.interpreted; import jetbrains.mps.smodel.Language; import jetbrains.mps.smodel.LanguageAspect; import jetbrains.mps.smodel.SNodeUtil; import jetbrains.mps.smodel.adapter.ids.MetaIdByDeclaration; import jetbrains.mps.smodel.adapter.ids.SConceptId; import jetbrains.mps.smodel.adapter.structure.concept.SConceptAdapterById; import jetbrains.mps.smodel.runtime.BaseStructureAspectDescriptor; import jetbrains.mps.smodel.runtime.ConceptDescriptor; import jetbrains.mps.util.NameUtil; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.jetbrains.mps.openapi.language.SConcept; import org.jetbrains.mps.openapi.model.SModel; import org.jetbrains.mps.openapi.model.SNode; import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * Migration and bootstrap structure utility. Initialized once, intentionally doesn't track * model changed as its primary purpose is to facilitate initial model loading when MPS 3.1 projects with * cleaned classes and sources get migrated to 3.2. Once migrated, languages are generated and * compiled StructureAspectDescriptors are in use. */ public class StructureAspectInterpreted extends BaseStructureAspectDescriptor { private static final Logger LOG = LogManager.getLogger(StructureAspectInterpreted.class); private volatile Map<SConceptId, ConceptDescriptor> myDescriptors; private volatile Map<String, ConceptDescriptor> myDescriptorByName; private final Language myLanguage; public StructureAspectInterpreted(Language language) { myLanguage = language; } @Override public Collection<ConceptDescriptor> getDescriptors() { ensureInitialized(); return myDescriptors.values(); } @Override public ConceptDescriptor getDescriptor(SConceptId id) { ensureInitialized(); return myDescriptors.get(id); } @Override public ConceptDescriptor getDescriptor(String fqName) { ensureInitialized(); return myDescriptorByName.get(fqName); } protected void ensureInitialized() { if (myDescriptors != null) { return; } jetbrains.mps.smodel.ModelAccess.instance().runReadAction(new Runnable() { @Override public void run() { if (myDescriptors != null) { return; } synchronized (StructureAspectInterpreted.this) { if (myDescriptors != null) { return; } final SModel structureModel = LanguageAspect.STRUCTURE.get(myLanguage); if (structureModel == null) { LOG.warn("Structure aspect is null in the language " + myLanguage); myDescriptorByName = new ConcurrentHashMap<String, ConceptDescriptor>(); myDescriptors = new ConcurrentHashMap<SConceptId, ConceptDescriptor>(); return; } ConcurrentHashMap<SConceptId, ConceptDescriptor> descriptors = new ConcurrentHashMap<SConceptId, ConceptDescriptor>(); ConcurrentHashMap<String, ConceptDescriptor> descriptorsByName = new ConcurrentHashMap<String, ConceptDescriptor>(); for (SNode root : structureModel.getRootNodes()) { SConcept concept = root.getConcept(); if (!isConceptDeclaration(concept)) { continue; } SConceptId conceptId = MetaIdByDeclaration.getConceptId(root); String conceptName = conceptFQName(root); ConceptDescriptor cd = new InterpretedConceptDescriptor(root, conceptId, conceptName); descriptors.put(conceptId, cd); descriptorsByName.put(conceptName, cd); } myDescriptorByName = descriptorsByName; myDescriptors = descriptors; } } }); } //this allows to get concept fq name w/o trying constraints //uses the fact that concept's name can't be overridden in constraints public static String conceptFQName(SNode node) { if (node == null) { return null; } String name = node.getProperty(SNodeUtil.property_INamedConcept_name); SModel model = node.getModel(); if (model == null) return name; return NameUtil.getModelLongName(model) + "." + name; } //this method MUST NOT call any concept methods (not to get into infinite recursion) private boolean isConceptDeclaration(SConcept concept) { if (concept instanceof SConceptAdapterById) { return concept.equals(SNodeUtil.concept_ConceptDeclaration) || concept.equals(SNodeUtil.concept_InterfaceConceptDeclaration); } else { throw new IllegalArgumentException(concept.getClass().getName()); } } }