/* * 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.base; import jetbrains.mps.smodel.adapter.ids.MetaIdHelper; import jetbrains.mps.smodel.adapter.ids.SConceptId; import jetbrains.mps.smodel.adapter.ids.SReferenceLinkId; import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory; import jetbrains.mps.smodel.adapter.structure.concept.SAbstractConceptAdapter; import jetbrains.mps.smodel.language.ConceptRegistry; import jetbrains.mps.smodel.runtime.ConceptDescriptor; import jetbrains.mps.smodel.runtime.ConstraintsDescriptor; import jetbrains.mps.smodel.runtime.InheritanceIterable; import jetbrains.mps.smodel.runtime.PropertyConstraintsDispatchable; import jetbrains.mps.smodel.runtime.ReferenceConstraintsDescriptor; import jetbrains.mps.smodel.runtime.ReferenceConstraintsDispatchable; import jetbrains.mps.smodel.runtime.ReferenceDescriptor; import jetbrains.mps.smodel.runtime.ReferenceScopeProvider; import jetbrains.mps.util.IterableUtil; import jetbrains.mps.util.annotation.ToRemove; import org.jetbrains.annotations.Nullable; import org.jetbrains.mps.openapi.language.SAbstractConcept; import org.jetbrains.mps.openapi.language.SConcept; import org.jetbrains.mps.openapi.language.SInterfaceConcept; import org.jetbrains.mps.openapi.language.SReferenceLink; import org.jetbrains.mps.openapi.model.SNode; import java.util.HashSet; import java.util.Set; public class BaseReferenceConstraintsDescriptor implements ReferenceConstraintsDispatchable { private final SReferenceLink myReferenceLink; private final ConstraintsDescriptor container; private final ReferenceConstraintsDescriptor scopeProviderDescriptor; private final ReferenceConstraintsDescriptor onReferenceSetHandlerDescriptor; @Deprecated @ToRemove(version = 3.4) public BaseReferenceConstraintsDescriptor(SReferenceLinkId referenceLink, ConstraintsDescriptor container) { this(MetaAdapterFactory.getReferenceLink(referenceLink, getNameDeprecated(referenceLink, container)), container); } private static String getNameDeprecated(SReferenceLinkId referenceLink, ConstraintsDescriptor container) { String name = "<UnknownRefName_BaseReferenceConstraintsDescriptor>"; ConceptDescriptor cd = ((SAbstractConceptAdapter) container.getConcept()).getConceptDescriptor(); if (cd == null) { return name; } ReferenceDescriptor ref = cd.getRefDescriptor(referenceLink); if (ref == null) { return name; } return ref.getName(); } public BaseReferenceConstraintsDescriptor(SReferenceLink referenceLink, ConstraintsDescriptor container) { this.myReferenceLink = referenceLink; this.container = container; if (hasOwnScopeProvider()) { scopeProviderDescriptor = this; } else { scopeProviderDescriptor = getSomethingUsingInheritance(getContainer().getConcept(), referenceLink, SCOPE_INHERITANCE_PARAMETERS); } if (hasOwnOnReferenceSetHandler()) { onReferenceSetHandlerDescriptor = this; } else { onReferenceSetHandlerDescriptor = getSomethingUsingInheritance(getContainer().getConcept(), referenceLink, ON_SET_HANDLER_INHERITANCE_PARAMETERS); } } @Nullable private static ReferenceConstraintsDescriptor getSomethingUsingInheritance(SAbstractConcept concept, SReferenceLink referenceLinkId, InheritanceCalculateParameters parameters) { for (SAbstractConcept parent : new InheritanceIterable(concept)) { if (!((SAbstractConceptAdapter) parent).hasReference(referenceLinkId)) { continue; } ConstraintsDescriptor parentDescriptor = ConceptRegistry.getInstance().getConstraintsDescriptor(parent); ReferenceConstraintsDescriptor parentReferenceDescriptor = parentDescriptor.getReference(referenceLinkId); ReferenceConstraintsDescriptor parentCalculated; if (parentReferenceDescriptor instanceof BaseReferenceConstraintsDescriptor) { parentCalculated = parameters.getParentCalculatedDescriptor((BaseReferenceConstraintsDescriptor) parentReferenceDescriptor); } else if (parentReferenceDescriptor instanceof PropertyConstraintsDispatchable) { if (parameters.hasOwn((ReferenceConstraintsDispatchable) parentReferenceDescriptor)) { parentCalculated = parentReferenceDescriptor; } else { parentCalculated = getSomethingUsingInheritance(parent, referenceLinkId, parameters); } } else { parentCalculated = parentReferenceDescriptor; } if (parentCalculated != null) { return parentCalculated; } } return null; } @Deprecated @ToRemove(version = 3.4) @Override public SReferenceLinkId getReferenceLink() { return MetaIdHelper.getAssociation(myReferenceLink); } @Override public SReferenceLink getReference() { return myReferenceLink; } @Override public String getName() { return myReferenceLink.getName(); } @Override public ConstraintsDescriptor getContainer() { return container; } @Nullable @Override public ReferenceScopeProvider getScopeProvider() { return scopeProviderDescriptor != null ? scopeProviderDescriptor.getScopeProvider() : null; } @Override public boolean validate(SNode referenceNode, SNode oldReferentNode, SNode newReferentNode) { return onReferenceSetHandlerDescriptor == null || onReferenceSetHandlerDescriptor.validate(referenceNode, oldReferentNode, newReferentNode); } @Override public void onReferenceSet(SNode referenceNode, SNode oldReferentNode, SNode newReferentNode) { if (onReferenceSetHandlerDescriptor != null) { onReferenceSetHandlerDescriptor.onReferenceSet(referenceNode, oldReferentNode, newReferentNode); } } @Override public boolean hasOwnScopeProvider() { return false; } @Override public boolean hasOwnOnReferenceSetHandler() { return false; } private static interface InheritanceCalculateParameters { ReferenceConstraintsDescriptor getParentCalculatedDescriptor(BaseReferenceConstraintsDescriptor parentDescriptor); boolean hasOwn(ReferenceConstraintsDispatchable parentDescriptor); } private static final InheritanceCalculateParameters SCOPE_INHERITANCE_PARAMETERS = new InheritanceCalculateParameters() { @Override public ReferenceConstraintsDescriptor getParentCalculatedDescriptor(BaseReferenceConstraintsDescriptor parentDescriptor) { return parentDescriptor.scopeProviderDescriptor; } @Override public boolean hasOwn(ReferenceConstraintsDispatchable parentDescriptor) { return parentDescriptor.hasOwnScopeProvider(); } }; private static final InheritanceCalculateParameters ON_SET_HANDLER_INHERITANCE_PARAMETERS = new InheritanceCalculateParameters() { @Override public ReferenceConstraintsDescriptor getParentCalculatedDescriptor(BaseReferenceConstraintsDescriptor parentDescriptor) { return parentDescriptor.onReferenceSetHandlerDescriptor; } @Override public boolean hasOwn(ReferenceConstraintsDispatchable parentDescriptor) { return parentDescriptor.hasOwnOnReferenceSetHandler(); } }; }