package jetbrains.mps.persistence.java.library;
/*Generated by MPS */
import jetbrains.mps.smodel.RegularModelDescriptor;
import jetbrains.mps.extapi.persistence.ModelSourceChangeTracker;
import org.jetbrains.mps.openapi.model.SModelReference;
import jetbrains.mps.extapi.persistence.FolderSetDataSource;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.module.SRepository;
import org.jetbrains.annotations.Nullable;
import jetbrains.mps.project.AbstractModule;
import jetbrains.mps.smodel.loading.ModelLoadingState;
import jetbrains.mps.smodel.SModel;
import jetbrains.mps.baseLanguage.javastub.ASMModelLoader;
import jetbrains.mps.smodel.nodeidmap.ForeignNodeIdMap;
import java.util.Collection;
import jetbrains.mps.smodel.loading.PartialModelUpdateFacility;
import jetbrains.mps.smodel.ModelLoadResult;
import org.jetbrains.mps.openapi.language.SLanguage;
import java.util.Set;
import java.util.Collections;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;
import java.util.List;
import org.jetbrains.mps.openapi.module.SModuleReference;
import org.jetbrains.mps.openapi.module.SModule;
import jetbrains.mps.extapi.module.SModuleBase;
public class JavaClassStubModelDescriptor extends RegularModelDescriptor implements ModelSourceChangeTracker.ReloadCallback {
private final ModelSourceChangeTracker myTimestampTracker;
private boolean mySkipPrivate;
/**
* tracks nested load() calls from within PartialModelUpdateFacility#update
* XXX would be nice to check update mode in LazySNode and not to demand enforceFullLoad() in this case
*/
private boolean myIsLoadInProgress;
public JavaClassStubModelDescriptor(SModelReference modelReference, FolderSetDataSource source) {
super(modelReference, source);
myTimestampTracker = new ModelSourceChangeTracker(this);
}
@Override
public void attach(@NotNull SRepository repository) {
super.attach(repository);
myTimestampTracker.attach(this);
}
@Override
public void detach() {
myTimestampTracker.detach(this);
super.detach();
}
/*package*/ void setSkipPrivate(boolean skipPrivateMembers) {
mySkipPrivate = skipPrivateMembers;
}
@NotNull
@Override
public FolderSetDataSource getSource() {
return (FolderSetDataSource) super.getSource();
}
@Nullable
@Override
public AbstractModule getModule() {
return (AbstractModule) super.getModule();
}
@Override
public void load() {
if (getLoadingState() != ModelLoadingState.FULLY_LOADED) {
final ModelLoadingState oldState;
synchronized (myLoadLock) {
if (myIsLoadInProgress) {
// we are inside nested load() within update
// the check shall be inside synchronized block, otherwise any other thread won't block on load
return;
}
final SModel mi = getSModelInternal();
oldState = getLoadingState();
if (oldState == ModelLoadingState.FULLY_LOADED) {
// another thread succeeded first
return;
}
myIsLoadInProgress = true;
ASMModelLoader loader = new ASMModelLoader(getModule(), getSource().getPaths());
loader.skipPrivateMembers(mySkipPrivate);
SModel completeModelData = new SModel(getReference(), new ForeignNodeIdMap());
Collection<SModelReference> imports = loader.completeModel(this, completeModelData);
completeModelData.enterUpdateMode();
mi.enterUpdateMode();
new PartialModelUpdateFacility(mi, completeModelData, this).update();
for (SModelReference mr : imports) {
mi.addModelImport(new SModel.ImportElement(mr));
}
completeModelData.leaveUpdateMode();
mi.leaveUpdateMode();
setLoadingState(ModelLoadingState.FULLY_LOADED);
myIsLoadInProgress = false;
}
fireModelStateChanged(oldState, getLoadingState());
}
}
@Override
@NotNull
protected ModelLoadResult<SModel> createModel() {
SModel model = new SModel(getReference(), new ForeignNodeIdMap());
for (SLanguage l : getLanguagesToImport()) {
model.addLanguage(l);
}
ASMModelLoader loader = new ASMModelLoader(getModule(), getSource().getPaths());
loader.skipPrivateMembers(mySkipPrivate);
loader.populateRoots(model);
return new ModelLoadResult<SModel>(model, ModelLoadingState.INTERFACE_LOADED);
}
private Set<SLanguage> getLanguagesToImport() {
return Collections.singleton(MetaAdapterFactory.getLanguage(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, "jetbrains.mps.baseLanguage"));
}
@Override
public Collection<SLanguage> importedLanguageIds() {
return getLanguagesToImport();
}
@Override
public List<SModuleReference> importedDevkits() {
return Collections.emptyList();
}
@Override
public void reloadFromDiskSafe() {
assertCanChange();
if (getSource().getPaths().isEmpty()) {
SModule module = getModule();
if (module instanceof SModuleBase) {
((SModuleBase) module).unregisterModel(this);
}
return;
}
reload();
myTimestampTracker.updateTimestamp(getSource());
}
private void reload() {
final SModel oldModel = getCurrentModelInternal();
if (oldModel == null) {
return;
}
// XXX shall I synchronize(myLoadLock) so that unload and subsequent partial load are from the same thread? I'm in the write anyway.
replace(createModel());
}
@Override
public String toString() {
return "JavaClassStubModelDescriptor " + getName();
}
}