Created
January 30, 2014 19:40
-
-
Save vorburger/8717137 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Copyright (c) 2014 Michael Vorburger 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 | |
* | |
* Contributors: Michael Vorburger - Initial API and implementation | |
*/ | |
package ch.vorburger.xtext.utils; | |
import java.util.ArrayList; | |
import java.util.List; | |
import org.eclipse.emf.common.notify.Adapter; | |
import org.eclipse.emf.common.util.TreeIterator; | |
import org.eclipse.emf.ecore.EObject; | |
import org.eclipse.emf.ecore.resource.Resource; | |
import org.eclipse.xtext.nodemodel.INode; | |
import org.eclipse.xtext.resource.XtextResource; | |
import org.eclipse.xtext.util.OnChangeEvictingCache.CacheAdapter; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
/** | |
* Util to remove Xtext Parse Tree Nodes. | |
* | |
* Useful to save memory, when not needed (e.g. in a Generator, but NOT in the UI). | |
* | |
* @author Michael Vorburger | |
*/ | |
public class NodesZapper { | |
private static final Logger logger = LoggerFactory.getLogger(NodesZapper.class); | |
public void removeNodeModel(Resource r) { | |
if (!(r instanceof XtextResource)) { | |
return; | |
} | |
XtextResource xr = (XtextResource) r; | |
// If there are errors or warnings, it's maybe safer not to remove the Node Model | |
// as keeping it may make it easier to find the (location of) the source of such errors. | |
if (!r.getErrors().isEmpty()) { | |
logger.warn("removeNodeModel() will *NOT* remove parse tree nodes, because there are errors on this resource: {}", r.getURI()); | |
return; | |
} | |
if (!r.getWarnings().isEmpty()) { | |
logger.warn("removeNodeModel() will *NOT* remove parse tree nodes, because there are warnings on this resource: {}", r.getURI()); | |
return; | |
} | |
TreeIterator<EObject> allContents = r.getAllContents(); | |
while (allContents.hasNext()) { | |
EObject eObj = allContents.next(); | |
// We cannot remove during the iteration over the adapters, else | |
// we'd get a ConcurrentModificationException, so we do it after: | |
List<Adapter> nodeAdaptersToRemove = new ArrayList<Adapter>(1); | |
for (Adapter adapter : eObj.eAdapters()) { | |
if (adapter instanceof INode) { | |
nodeAdaptersToRemove.add(adapter); | |
} else if (adapter instanceof CacheAdapter) { | |
// removing these seems more risk than gain | |
// In measure with >10k models, it makes only a tiny difference | |
// SO DO NOTHING for these (but don't log below them either) | |
} else { | |
logger.info("Found unexpected non-INode/CacheAdapter Adapter, ignoring it (not removing; still consumes memory): {}", adapter.getClass().getName()); | |
} | |
} | |
if (!nodeAdaptersToRemove.isEmpty()) { | |
for (Adapter adapter : nodeAdaptersToRemove) { | |
eObj.eAdapters().remove(adapter); | |
} | |
nodeAdaptersToRemove.clear(); | |
} | |
} | |
xr.setParseResult(null); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment