/* * Copyright 2003-2014 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.persistence.def.v9; import org.apache.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.mps.openapi.model.SModelReference; import java.util.HashMap; import java.util.Set; /** * Keeps information about model imports. Both write and read code use this to track * model imports and their respective index values. * * The way model imports as well as node references utilizing these imports get serialized * is external to this class, see {@link jetbrains.mps.smodel.persistence.def.v9.IdEncoder#toTextExternal(ImportsHelper, org.jetbrains.mps.openapi.model.SReference)} ` * * Alternative to StorageIndexHelper9, index generation code (although questionable) is identical. */ class ImportsHelper { private final SModelReference myModelRef; private final HashMap<SModelReference, String> myModel2Index = new HashMap<SModelReference, String>(); private final HashMap<String, SModelReference> myIndex2Model = new HashMap<String, SModelReference>(); private static final int HASH_BASE = 10 + 26; private static final int HASH_SIZE = HASH_BASE * HASH_BASE * HASH_BASE * HASH_BASE; public ImportsHelper(@NotNull SModelReference model) { myModelRef = model; } public String addModelImport(@NotNull SModelReference modelReference) { if (myModel2Index.containsKey(modelReference)) { // assert !myModel2Index.containsKey(modelReference); Logger.getLogger(ImportsHelper.class).error(String.format("Model %s has duplicating import %s, ignored", myModelRef, modelReference)); return myModel2Index.get(modelReference); } String rv = createIndexFor(modelReference.getModelId().hashCode(), myIndex2Model.keySet()); register(rv, modelReference); return rv; } public void addModelImport(@NotNull String index, @NotNull SModelReference modelReference) { if (myIndex2Model.containsKey(index)) { // throw new IllegalArgumentException(String.format...); Logger.getLogger(ImportsHelper.class).error(String.format("Can't register import %s in model %s. Index %s is already in use for model %s", modelReference, myModelRef, index, myIndex2Model.get(index))); return; } register(index, modelReference); } public String getIndex(@NotNull SModelReference modelReference) { assert myModel2Index.containsKey(modelReference) : String.valueOf(modelReference); return myModel2Index.get(modelReference); } public SModelReference getModelReference(@NotNull String index) { assert myIndex2Model.containsKey(index); return myIndex2Model.get(index); } // algorithm copied from StorageIndexHelper9.addInternalObject /** * Return value shall not use symbols other than [0-9][a-z] as the index is serialized as part of node identification, * with {@link jetbrains.mps.smodel.persistence.def.v9.IdEncoder#REF_TARGET_IMPORT_SEPARATOR} as separator */ private String createIndexFor(int initialHash, Set<String> usedIndex) { int hash = (initialHash % HASH_SIZE + HASH_SIZE) % HASH_SIZE; String rv; do { rv = Integer.toString(hash, HASH_BASE); hash = (hash + 1) % HASH_SIZE; } while (usedIndex.contains(rv)); return rv; } private void register(String index, SModelReference modelReference) { if (myModelRef.equals(modelReference)) { // assert !myModelRef.equals(modelReference) : String.format("Model %s: no reason to keep imports to self", myModelRef); Logger.getLogger(ImportsHelper.class).error(String.format("Model %s: no reason to keep imports to self", myModelRef)); } myIndex2Model.put(index, modelReference); myModel2Index.put(modelReference, index); } public boolean isLocal(SModelReference targetModel) { return targetModel.equals(myModelRef); } public SModelReference localModel() { return myModelRef; } }