package jetbrains.mps.ide.java.sourceStubs; /*Generated by MPS */ import jetbrains.mps.smodel.RegularModelDescriptor; import org.jetbrains.mps.openapi.persistence.MultiStreamDataSourceListener; import jetbrains.mps.logging.Logger; import org.apache.log4j.LogManager; import java.util.Map; import java.util.Set; import org.jetbrains.mps.openapi.model.SNode; import jetbrains.mps.internal.collections.runtime.MapSequence; import java.util.HashMap; import org.jetbrains.mps.openapi.model.SNodeId; import org.jetbrains.mps.openapi.model.SModelReference; import org.jetbrains.mps.openapi.persistence.MultiStreamDataSource; import org.jetbrains.annotations.NotNull; import jetbrains.mps.smodel.ModelLoadResult; import jetbrains.mps.smodel.SModel; import org.jetbrains.mps.openapi.language.SLanguage; import jetbrains.mps.internal.collections.runtime.CollectionSequence; import jetbrains.mps.smodel.loading.ModelLoadingState; import org.jetbrains.mps.openapi.module.SRepository; import org.jetbrains.mps.openapi.persistence.DataSource; import jetbrains.mps.extapi.model.SModelData; import jetbrains.mps.ide.java.newparser.JavaParser; import jetbrains.mps.internal.collections.runtime.SetSequence; import java.util.HashSet; import java.io.InputStream; import jetbrains.mps.internal.collections.runtime.IVisitor; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations; import java.io.IOException; import jetbrains.mps.ide.java.newparser.FeatureKind; import jetbrains.mps.internal.collections.runtime.ListSequence; import jetbrains.mps.internal.collections.runtime.IWhereFilter; import jetbrains.mps.ide.java.newparser.JavaParseException; import jetbrains.mps.progress.EmptyProgressMonitor; import java.util.List; import java.util.LinkedList; import java.util.Collection; import java.util.Collections; import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory; import org.jetbrains.mps.openapi.module.SModuleReference; public class JavaSourceStubModelDescriptor extends RegularModelDescriptor implements MultiStreamDataSourceListener { private static Logger LOG = Logger.wrap(LogManager.getLogger(JavaSourceStubModelDescriptor.class)); private boolean myIsLoadInProgress = false; private Map<String, Set<SNode>> myRootsPerFile = MapSequence.fromMap(new HashMap<String, Set<SNode>>()); private Map<SNodeId, SNode> myRootsById = MapSequence.fromMap(new HashMap<SNodeId, SNode>()); public JavaSourceStubModelDescriptor(SModelReference modelRef, MultiStreamDataSource dataSource) { super(modelRef, dataSource); } @Override @NotNull protected ModelLoadResult<SModel> createModel() { SModel model = new SModel(getReference()); processStreams(getSource().getAvailableStreams(), model); for (SLanguage l : CollectionSequence.fromCollection(importedLanguageIds())) { model.addLanguage(l); } return new ModelLoadResult<SModel>(model, ModelLoadingState.NO_IMPLEMENTATION); } @Override public void attach(SRepository repository) { getSource().addListener(this); super.attach(repository); } @Override public void detach() { super.detach(); getSource().removeListener(this); } @Override @NotNull public MultiStreamDataSource getSource() { return (MultiStreamDataSource) super.getSource(); } @Override public void changed(DataSource source, Iterable<String> changedItems) { // FIXME it works, but is not incremental and is ugly assertCanChange(); SModel oldModel = getCurrentModelInternal(); // already attached but not createModel'd yet if (oldModel == null) { return; } MapSequence.fromMap(myRootsPerFile).clear(); MapSequence.fromMap(myRootsById).clear(); replace(createModel()); } @Override public void changed(DataSource source) { // ignore } public void processStreams(Iterable<String> names, SModelData into) { JavaParser parser = new JavaParser(); for (String fileName : names) { try { Set<SNode> oldNodes = SetSequence.fromSetWithValues(new HashSet<SNode>(), MapSequence.fromMap(myRootsPerFile).get(fileName)); InputStream is = getSource().openInputStream(fileName); // we've come from event and file has been deleted if (is == null) { SetSequence.fromSet(oldNodes).visitAll(new IVisitor<SNode>() { public void visit(SNode it) { SNodeOperations.deleteNode(it); } }); MapSequence.fromMap(myRootsPerFile).removeKey(fileName); continue; } String code = readInputStream(is); try { is.close(); } catch (IOException e) { LOG.warning("failed to close file " + fileName, e); } JavaParser.JavaParseResult parseResult = parser.parse(code, FeatureKind.CLASS_STUB, null, true); if (ListSequence.fromList(parseResult.getNodes()).isNotEmpty()) { for (SNode newNode : ListSequence.fromList(parseResult.getNodes())) { final SNodeId newNodeId = newNode.getNodeId(); // oldNodes is usually very very small (number of root classes in java file) SNode oldNode = SetSequence.fromSet(oldNodes).where(new IWhereFilter<SNode>() { public boolean accept(SNode it) { return it.getNodeId().equals(newNodeId); } }).first(); if (oldNode == null) { into.addRootNode(newNode); SetSequence.fromSet(oldNodes).removeElement(oldNode); } else { SNodeOperations.replaceWithAnother(oldNode, newNode); } MapSequence.fromMap(myRootsById).put(newNode.getNodeId(), newNode); } } SetSequence.fromSet(oldNodes).visitAll(new IVisitor<SNode>() { public void visit(SNode it) { SNodeOperations.deleteNode(it); } }); MapSequence.fromMap(myRootsPerFile).put(fileName, SetSequence.fromSetWithValues(new HashSet<SNode>(), parseResult.getNodes())); } catch (IOException e) { LOG.error("Failed to read java file. " + e.getMessage(), e); } catch (JavaParseException e) { LOG.error("Failed to parse java file. " + e.getMessage()); } } } @Override public void load() { if (getLoadingState() == ModelLoadingState.FULLY_LOADED) { return; } synchronized (myLoadLock) { if (myIsLoadInProgress) { return; } ModelLoadingState oldState = getLoadingState(); if (oldState == ModelLoadingState.FULLY_LOADED) { // double check return; } SModel mi = getSModelInternal(); try { myIsLoadInProgress = true; mi.enterUpdateMode(); JavaParser.tryResolveUnknowns(MapSequence.fromMap(myRootsById).values(), new EmptyProgressMonitor()); setLoadingState(ModelLoadingState.FULLY_LOADED); fireModelStateChanged(oldState, ModelLoadingState.FULLY_LOADED); } finally { mi.leaveUpdateMode(); myIsLoadInProgress = false; } } } private static final int BUFSIZE = 65536; private String readInputStream(InputStream is) throws IOException { List<byte[]> blocks = ListSequence.fromList(new LinkedList<byte[]>()); byte[] buffer = new byte[BUFSIZE]; int lastRead = -1; int read = is.read(buffer); while (read > 0) { lastRead = read; ListSequence.fromList(blocks).addElement(buffer); buffer = new byte[BUFSIZE]; read = is.read(buffer); } if (lastRead > 0) { int blks = ListSequence.fromList(blocks).count(); byte[] wholeBuffer; if (blks == 1) { wholeBuffer = ListSequence.fromList(blocks).getElement(0); } else { int size = (blks - 1) * BUFSIZE + lastRead; wholeBuffer = new byte[size]; int c = 0; int p = 0; for (byte[] buf : blocks) { int n = (c == blks - 1 ? lastRead : BUFSIZE); System.arraycopy(buf, 0, wholeBuffer, p, n); p = p + BUFSIZE; c++; } } // Attention: default platform charset used. return new String(wholeBuffer); } else { return ""; } } @Override public Collection<SLanguage> importedLanguageIds() { return Collections.singleton(MetaAdapterFactory.getLanguage(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, "jetbrains.mps.baseLanguage")); } @Override public List<SModuleReference> importedDevkits() { return Collections.emptyList(); } }