Merge "[storage] store DocumentationAdapter, optionally persist node model (off by default). Fixes broken hover (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=456857)"

This commit is contained in:
Dennis Huebner 2015-01-22 09:14:12 -05:00 committed by Gerrit Code Review @ Eclipse.org
commit 70873885e0
4 changed files with 167 additions and 30 deletions

View file

@ -0,0 +1,50 @@
/*******************************************************************************
* Copyright (c) 2010 itemis AG (http://www.itemis.eu) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.xtext.junit4.util;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl;
import org.eclipse.xtext.util.StringInputStream;
/**
* A {@link org.eclipse.emf.ecore.resource.URIConverter} that can create input streams
* for synthetic URIs based on previously registered mappings.
*
* @author Sebastian Zarnekow - Initial contribution and API
* @since 2.8
*/
public class InMemoryURIConverter extends ExtensibleURIConverterImpl {
private final Map<URI, InputStream> models = new HashMap<URI, InputStream>();
public void addModel(String uri, String content) {
models.put(URI.createURI(uri), new StringInputStream(content));
}
@Override
public boolean exists(URI uri, Map<?, ?> options) {
boolean result = models.containsKey(uri);
if (!result) {
for(URI knownUri: models.keySet()) {
if (uri.toString().endsWith(knownUri.toString()))
return true;
}
}
return result;
}
@Override
public InputStream createInputStream(URI uri, Map<?, ?> options) throws IOException {
return models.get(uri);
}
}

View file

@ -18,6 +18,7 @@ import org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl
import org.eclipse.xtext.generator.AbstractFileSystemAccess2
import org.eclipse.xtext.generator.IContextualOutputConfigurationProvider
import org.eclipse.xtext.generator.IFileSystemAccessExtension3
import org.eclipse.xtend.lib.annotations.Accessors
/**
* @author Sven Efftinge - Initial contribution and API
@ -27,6 +28,7 @@ class ResourceStorageFacade implements IResourceStorageFacade {
@Inject IContextualOutputConfigurationProvider outputConfigurationProvider
@Inject Provider<AbstractFileSystemAccess2> fileSystemAccessProvider
@Accessors boolean storeNodeModel = false
/**
* @return whether the given resource should be loaded from stored resource state
*/
@ -74,11 +76,11 @@ class ResourceStorageFacade implements IResourceStorageFacade {
}
override def ResourceStorageLoadable createResourceStorageLoadable(InputStream in) {
return new ResourceStorageLoadable(in)
return new ResourceStorageLoadable(in, isStoreNodeModel)
}
override def ResourceStorageWritable createResourceStorageWritable(OutputStream out) {
return new ResourceStorageWritable(out)
return new ResourceStorageWritable(out, isStoreNodeModel)
}
/**

View file

@ -7,22 +7,31 @@
*******************************************************************************/
package org.eclipse.xtext.resource.persistence
import com.google.common.io.CharStreams
import java.io.DataInputStream
import java.io.IOException
import java.io.InputStream
import java.io.InputStreamReader
import java.io.ObjectInputStream
import java.util.zip.ZipInputStream
import org.apache.log4j.Logger
import org.eclipse.emf.ecore.InternalEObject
import org.eclipse.emf.ecore.resource.impl.BinaryResourceImpl
import org.eclipse.xtend.lib.annotations.Data
import org.eclipse.emf.ecore.resource.impl.BinaryResourceImpl.EObjectInputStream
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
import org.eclipse.xtext.nodemodel.impl.SerializableNodeModel
import org.eclipse.xtext.nodemodel.serialization.DeserializationConversionContext
import org.eclipse.xtext.parser.ParseResult
/**
* @author Sven Efftinge - Initial contribution and API
*/
@Data class ResourceStorageLoadable {
@FinalFieldsConstructor class ResourceStorageLoadable {
static val LOG = Logger.getLogger(ResourceStorageLoadable)
InputStream in
val InputStream in
val boolean storeNodeModel
protected def void loadIntoResource(StorageAwareResource resource) {
try {
@ -45,21 +54,20 @@ import org.eclipse.xtend.lib.annotations.Data
* Overriding methods should first delegate to super before adding their own entries.
*/
protected def void loadEntries(StorageAwareResource resource, ZipInputStream zipIn) {
zipIn.nextEntry
readContents(resource, zipIn)
zipIn.nextEntry
readResourceDescription(resource, zipIn)
if (storeNodeModel) {
zipIn.nextEntry
readNodeModel(resource, zipIn)
}
}
protected def void readResourceDescription(StorageAwareResource resource, ZipInputStream zipIn) {
zipIn.nextEntry
val objectIn = new ObjectInputStream(zipIn)
val description = objectIn.readObject as SerializableResourceDescription
description.updateResourceURI(resource.URI)
resource.resourceDescription = description
}
protected def void readContents(StorageAwareResource resource, ZipInputStream zipIn) {
zipIn.nextEntry
val in = new BinaryResourceImpl.EObjectInputStream(zipIn, emptyMap) {
protected def void readContents(StorageAwareResource resource, InputStream inputStream) {
val in = new BinaryResourceImpl.EObjectInputStream(inputStream, emptyMap) {
override readCompressedInt() throws IOException {
//HACK! null resource set, to avoid usage of resourceSet's package registry
@ -67,8 +75,45 @@ import org.eclipse.xtend.lib.annotations.Data
super.readCompressedInt()
}
override loadEObject() throws IOException {
val result = super.loadEObject()
handleLoadEObject(result, this)
return result
}
}
in.loadResource(resource)
}
protected def handleLoadEObject(InternalEObject loaded, EObjectInputStream input) {
}
protected def void readResourceDescription(StorageAwareResource resource, InputStream inputStream) {
val objectIn = new ObjectInputStream(inputStream)
val description = objectIn.readObject as SerializableResourceDescription
description.updateResourceURI(resource.URI)
resource.resourceDescription = description
}
protected def void readNodeModel(StorageAwareResource resource, InputStream inputStream) {
try {
val serializableNodeModel = new SerializableNodeModel(resource)
// if this is a synthetic resource (i.e. tests or so, don't load the node model)
if (!resource.resourceSet.URIConverter.exists(resource.URI, resource.resourceSet.loadOptions)) {
LOG.info("Skipping loading node model for synthetic resource "+resource.URI)
return;
}
val stream = resource.resourceSet.URIConverter.createInputStream(resource.URI)
val in = new InputStreamReader(stream, resource.encoding)
val completeContent = CharStreams.toString(in)
val deserializationContext = new DeserializationConversionContext(resource, completeContent)
val dataIn = new DataInputStream(inputStream)
serializableNodeModel.readObjectData(dataIn, deserializationContext)
resource.parseResult = new ParseResult(resource.contents.head,serializableNodeModel.root, deserializationContext.hasErrors)
} catch (IOException e) {
LOG.error(e.message, e)
}
}
}

View file

@ -7,6 +7,7 @@
*******************************************************************************/
package org.eclipse.xtext.resource.persistence
import java.io.DataOutputStream
import java.io.IOException
import java.io.ObjectOutputStream
import java.io.OutputStream
@ -14,17 +15,21 @@ import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import org.apache.log4j.Logger
import org.eclipse.emf.common.util.URI
import org.eclipse.emf.ecore.InternalEObject
import org.eclipse.emf.ecore.resource.impl.BinaryResourceImpl
import org.eclipse.xtend.lib.annotations.Data
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
import org.eclipse.xtext.nodemodel.impl.SerializableNodeModel
import org.eclipse.xtext.nodemodel.serialization.SerializationConversionContext
/**
* @author Sven Efftinge - Initial contribution and API
*/
@Data class ResourceStorageWritable {
@FinalFieldsConstructor class ResourceStorageWritable {
static val LOG = Logger.getLogger(ResourceStorageWritable)
OutputStream out
val OutputStream out
val boolean storeNodeModel
def void writeResource(StorageAwareResource resource) {
if (resource.isLoadedFromStorage) {
@ -45,41 +50,68 @@ import org.eclipse.xtend.lib.annotations.Data
* Overriding methods should first delegate to super before adding their own entries.
*/
protected def void writeEntries(StorageAwareResource resource, ZipOutputStream zipOut) {
writeContents(resource, zipOut)
writeResourceDescription(resource, zipOut)
zipOut.putNextEntry(new ZipEntry("emf-contents"))
try {
writeContents(resource, zipOut)
} finally {
zipOut.closeEntry
}
zipOut.putNextEntry(new ZipEntry("resource-description"))
try {
writeResourceDescription(resource, zipOut)
} finally {
zipOut.closeEntry
}
if (storeNodeModel) {
zipOut.putNextEntry(new ZipEntry("node-model"))
try {
writeNodeModel(resource, zipOut)
} finally {
zipOut.closeEntry
}
}
}
protected def void writeContents(StorageAwareResource storageAwareResource, ZipOutputStream zipOut) {
zipOut.putNextEntry(new ZipEntry("emf-contents"))
val out = new BinaryResourceImpl.EObjectOutputStream(zipOut, emptyMap) {
protected def void writeContents(StorageAwareResource storageAwareResource, OutputStream outputStream) {
val out = new BinaryResourceImpl.EObjectOutputStream(outputStream, emptyMap) {
override writeURI(URI uri, String fragment) throws IOException {
val fullURI = uri.appendFragment(fragment)
val uriToWrite = storageAwareResource.portableURIs.toPortableURI(storageAwareResource, fullURI) ?: fullURI
super.writeURI(uriToWrite.trimFragment, uriToWrite.fragment)
}
override saveEObject(InternalEObject internalEObject, Check check) throws IOException {
super.saveEObject(internalEObject, check)
handleSaveEObject(internalEObject, this)
}
}
try {
out.saveResource(storageAwareResource)
} finally {
out.flush
}
zipOut.closeEntry
}
protected def void handleSaveEObject(InternalEObject object, BinaryResourceImpl.EObjectOutputStream out) {
// do nothing
}
protected def void writeResourceDescription(StorageAwareResource resource, ZipOutputStream zipOut) {
zipOut.putNextEntry(new ZipEntry("resource-description"))
protected def void writeResourceDescription(StorageAwareResource resource, OutputStream outputStream) {
val description = resource.resourceServiceProvider.resourceDescriptionManager.getResourceDescription(resource);
val serializableDescription = SerializableResourceDescription.createCopy(description)
convertExternalURIsToPortableURIs(serializableDescription, resource)
val out = new ObjectOutputStream(zipOut);
val out = new ObjectOutputStream(outputStream);
try {
out.writeObject(serializableDescription);
} finally {
out.flush
}
zipOut.closeEntry
}
def protected void convertExternalURIsToPortableURIs(SerializableResourceDescription description, StorageAwareResource resource) {
@ -90,4 +122,12 @@ import org.eclipse.xtend.lib.annotations.Data
}
}
protected def writeNodeModel(StorageAwareResource resource, OutputStream outputStream) {
val out = new DataOutputStream(outputStream);
val serializableNodeModel = new SerializableNodeModel(resource)
val conversionContext = new SerializationConversionContext(resource)
serializableNodeModel.writeObjectData(out, conversionContext)
out.flush
}
}