/* * Copyright 2003-2016 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.SNodeUtil; import jetbrains.mps.smodel.adapter.ids.SPropertyId; 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.PropertyConstraintsDescriptor; import jetbrains.mps.smodel.runtime.PropertyConstraintsDispatchable; import jetbrains.mps.smodel.runtime.PropertyDescriptor; import jetbrains.mps.util.annotation.ToRemove; import org.jetbrains.annotations.Nullable; import org.jetbrains.mps.openapi.language.SAbstractConcept; import org.jetbrains.mps.openapi.language.SProperty; import org.jetbrains.mps.openapi.model.SNode; public class BasePropertyConstraintsDescriptor implements PropertyConstraintsDispatchable { private final SProperty myProperty; private final ConstraintsDescriptor container; private final PropertyConstraintsDescriptor getterDescriptor; private final PropertyConstraintsDescriptor setterDescriptor; private final PropertyConstraintsDescriptor validatorDescriptor; @Deprecated @ToRemove(version = 3.4) public BasePropertyConstraintsDescriptor(SPropertyId property, ConstraintsDescriptor container) { this(MetaAdapterFactory.getProperty(property, getNameDeprecated(property, container)), container); } private static String getNameDeprecated(SPropertyId property, ConstraintsDescriptor container) { String name = "<UnknownPropName_BasePropertyConstraintsDescriptor>"; ConceptDescriptor cd = ((SAbstractConceptAdapter) container.getConcept()).getConceptDescriptor(); if (cd == null) { return name; } PropertyDescriptor prop = cd.getPropertyDescriptor(property); if (prop == null) { return name; } return prop.getName(); } public BasePropertyConstraintsDescriptor(SProperty property, ConstraintsDescriptor container) { this.myProperty = property; this.container = container; if (!isBootstrapProperty(container.getConcept(), property)) { if (hasOwnGetter()) { getterDescriptor = this; } else { getterDescriptor = getSomethingUsingInheritance(getContainer().getConcept(), property, GETTER_INHERITANCE_PARAMETERS); } if (hasOwnSetter()) { setterDescriptor = this; } else { setterDescriptor = getSomethingUsingInheritance(getContainer().getConcept(), property, SETTER_INHERITANCE_PARAMETERS); } } else { getterDescriptor = null; setterDescriptor = null; } if (hasOwnValidator()) { validatorDescriptor = this; } else { validatorDescriptor = getSomethingUsingInheritance(getContainer().getConcept(), property, VALIDATOR_INHERITANCE_PARAMETERS); } } @ToRemove(version = 3.5) private static boolean isBootstrapProperty(SAbstractConcept concept, SProperty property) { if (property.equals(SNodeUtil.property_INamedConcept_name) && concept.equals(SNodeUtil.concept_INamedConcept)) { return true; } if (property.getOwner().equals(SNodeUtil.concept_RuntimeTypeVariable)) { // helgins ku-ku! return true; } return false; } @Nullable private static PropertyConstraintsDescriptor getSomethingUsingInheritance(SAbstractConcept concept, SProperty property, InheritanceCalculateParameters parameters) { for (SAbstractConcept parent : new InheritanceIterable(concept)) { if (!((SAbstractConceptAdapter) parent).hasProperty(property)) { continue; } ConstraintsDescriptor parentDescriptor = ConceptRegistry.getInstance().getConstraintsDescriptor(parent); PropertyConstraintsDescriptor parentPropertyDescriptor = parentDescriptor.getProperty(property); PropertyConstraintsDescriptor parentCalculated; if (parentPropertyDescriptor instanceof BasePropertyConstraintsDescriptor) { parentCalculated = parameters.getParentCalculatedDescriptor((BasePropertyConstraintsDescriptor) parentPropertyDescriptor); } else if (parentPropertyDescriptor instanceof PropertyConstraintsDispatchable) { if (parameters.hasOwn((PropertyConstraintsDispatchable) parentPropertyDescriptor)) { parentCalculated = parentPropertyDescriptor; } else { parentCalculated = getSomethingUsingInheritance(parent, property, parameters); } } else { parentCalculated = parentPropertyDescriptor; } if (parentCalculated != null) { return parentCalculated; } } return null; } public boolean isSetterDefault() { return setterDescriptor == null; } public boolean isGetterDefault() { return getterDescriptor == null; } public boolean isValidatorDefault() { return validatorDescriptor == null; } @Override public boolean hasOwnGetter() { return false; } @Override public boolean hasOwnSetter() { return false; } @Override public boolean hasOwnValidator() { return false; } @Override public SProperty getSProperty() { return myProperty; } @Override public ConstraintsDescriptor getContainer() { return container; } @Override public Object getValue(SNode node) { if (!isGetterDefault()) { return getterDescriptor.getValue(node); } else { return node.getProperty(myProperty); } } @Override public void setValue(SNode node, String value) { if (!isSetterDefault()) { setterDescriptor.setValue(node, value); } else { node.setProperty(myProperty, value); } } @Override public boolean validateValue(SNode node, String value) { if (!isValidatorDefault()) { return validatorDescriptor.validateValue(node, value); } else { return true; } } @Override public boolean isReadOnly() { return isSetterDefault() && !isGetterDefault(); } private interface InheritanceCalculateParameters { PropertyConstraintsDescriptor getParentCalculatedDescriptor(BasePropertyConstraintsDescriptor parentDescriptor); boolean hasOwn(PropertyConstraintsDispatchable parentDescriptor); } private static final InheritanceCalculateParameters GETTER_INHERITANCE_PARAMETERS = new InheritanceCalculateParameters() { @Override public PropertyConstraintsDescriptor getParentCalculatedDescriptor(BasePropertyConstraintsDescriptor parentDescriptor) { return parentDescriptor.getterDescriptor; } @Override public boolean hasOwn(PropertyConstraintsDispatchable parentDescriptor) { return parentDescriptor.hasOwnGetter(); } }; private static final InheritanceCalculateParameters SETTER_INHERITANCE_PARAMETERS = new InheritanceCalculateParameters() { @Override public PropertyConstraintsDescriptor getParentCalculatedDescriptor(BasePropertyConstraintsDescriptor parentDescriptor) { return parentDescriptor.setterDescriptor; } @Override public boolean hasOwn(PropertyConstraintsDispatchable parentDescriptor) { return parentDescriptor.hasOwnSetter(); } }; private static final InheritanceCalculateParameters VALIDATOR_INHERITANCE_PARAMETERS = new InheritanceCalculateParameters() { @Override public PropertyConstraintsDescriptor getParentCalculatedDescriptor(BasePropertyConstraintsDescriptor parentDescriptor) { return parentDescriptor.validatorDescriptor; } @Override public boolean hasOwn(PropertyConstraintsDispatchable parentDescriptor) { return parentDescriptor.hasOwnValidator(); } }; }