/* * 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.project.structure.modules; import jetbrains.mps.project.structure.modules.mappingpriorities.MappingPriorityRule; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.mps.openapi.model.SModel; import org.jetbrains.mps.openapi.model.SModelReference; import org.jetbrains.mps.openapi.module.SModule; import org.jetbrains.mps.openapi.module.SModuleReference; import org.jetbrains.mps.openapi.module.SRepository; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; /** * Model/module name might get changed, and to reflect actual name in descriptor files, we 'update' references from time to time, * by resolving them into actual objects and re-obtaining the reference. */ public final class RefUpdateUtil { private final SRepository myRepository; /** * @param repository where to look actual modules/models up */ public RefUpdateUtil(@NotNull SRepository repository) { myRepository = repository; } public boolean updateModelRefs(Collection<SModelReference> refs) { Set<SModelReference> remove = new HashSet<SModelReference>(); Set<SModelReference> add = new LinkedHashSet<SModelReference>(); for (SModelReference ref : refs) { SModelReference newRef = updateModelRef(ref); if (newRef != null) { remove.add(ref); add.add(newRef); } } refs.removeAll(remove); refs.addAll(add); return !remove.isEmpty(); } /** * @return <code>null</code> if modelRef is unchanged or could not be updated, not <code>null</code> iff actual reference is different */ @Nullable public SModelReference updateModelRef(@NotNull SModelReference modelRef) { final SModel resolved = modelRef.resolve(myRepository); if (resolved == null) { return null; } final SModelReference actualModelRef = resolved.getReference(); return jetbrains.mps.smodel.SModelReference.differs(actualModelRef, modelRef) ? actualModelRef : null; } public boolean updateModuleRefs(Collection<SModuleReference> refs) { Set<SModuleReference> remove = new HashSet<SModuleReference>(); Set<SModuleReference> add = new LinkedHashSet<SModuleReference>(); for (SModuleReference ref : refs) { SModuleReference newRef = update(ref); if (ModuleReference.differs(ref, newRef)) { remove.add(ref); add.add(newRef); } } refs.removeAll(remove); refs.addAll(add); return !remove.isEmpty(); } // Perhaps, RUU could be kept generic, and ModuleDescriptor would take care of the owner class (Dependency) then? public boolean updateDependencies(Collection<Dependency> deps) { boolean changed = false; for (Dependency dep : deps) { SModuleReference ref = dep.getModuleRef(); @NotNull SModuleReference newRef = update(ref); if (ModuleReference.differs(ref, newRef)) { changed = true; dep.setModuleRef(newRef); } } return changed; } public boolean updateMappingPriorityRules(List<MappingPriorityRule> rules) { boolean changed = false; for (MappingPriorityRule rule : rules) { boolean result = rule.updateReferences(myRepository); changed = changed || result; } return changed; } public static boolean composeUpdates(boolean... values) { boolean changed = false; for (boolean v : values) { if (v) changed = true; } return changed; } // could be public if we decide this class shall be generic and do not deal with Dependency (@see #updateDependencies()) private SModuleReference update(SModuleReference reference) { SModule module = reference.resolve(myRepository); return module == null ? reference : module.getModuleReference(); } }