/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.core.workspace;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.core.designer.util.Stopwatch;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.container.Container;
import org.teiid.designer.core.container.DefaultContainerResourceSetFinder;
import org.teiid.designer.core.container.ResourceSetFinder;
import org.teiid.designer.core.resource.EmfResource;
import org.teiid.designer.core.resource.EmfResourceSet;
import org.teiid.designer.core.util.OverflowingLRUCache;
/**
* The buffer manager manages the set of open buffers.
* It implements an LRU cache of buffers.
*
* @since 8.0
*/
public class ModelBufferManager implements ModelBufferFactory {
protected static final int DEFAULT_MODEL_BUFFER_CACHE_LIMIT = 300;
private static ModelBufferManager DEFAULT_MODEL_BUFFER_MANAGER;
/**
* Returns the default buffer manager.
*/
public synchronized static ModelBufferManager getDefaultBufferManager() {
if (DEFAULT_MODEL_BUFFER_MANAGER == null) {
DEFAULT_MODEL_BUFFER_MANAGER = new ModelBufferManager();
}
return DEFAULT_MODEL_BUFFER_MANAGER;
}
/**
* Cache of buffers. The key and value for an entry
* in the table is the identical buffer.
*/
private final OverflowingLRUCache openBuffers;
/**
* The finder that is used to identify which {@link ResourceSet} should be used when creating
* a new {@link ModelBuffer}
*/
private ResourceSetFinder resourceSetFinder;
private final Map emfResourceToModelResource;
/**
* Creates a new buffer manager.
*/
public ModelBufferManager() {
this(DEFAULT_MODEL_BUFFER_CACHE_LIMIT);
}
/**
* Creates a new buffer manager with a custom size.
*/
protected ModelBufferManager( int cacheSize ) {
Stopwatch stopwatch = null;
if ( ModelerCore.DEBUG_MODEL_WORKSPACE ) {
stopwatch = new Stopwatch();
stopwatch.start();
}
this.openBuffers = new ModelBufferCache(cacheSize);
this.resourceSetFinder = new DefaultContainerResourceSetFinder();
if ( ModelerCore.DEBUG_MODEL_WORKSPACE ) {
stopwatch.stop();
ModelerCore.Util.log(IStatus.INFO,ModelerCore.Util.getString("ModelBufferManager.Time_to_create_ModelBufferManager",stopwatch)); //$NON-NLS-1$
}
this.emfResourceToModelResource = new HashMap();
}
protected void registerEmfResource( final Resource resource, final Openable openable ) {
this.emfResourceToModelResource.put(resource,openable);
}
protected void unregisterEmfResource( final Resource resource ) {
this.emfResourceToModelResource.remove(resource);
}
protected ModelResource getModelResource( final Resource resource ) {
// At this point, we know the resource is in the ModelContainer, so see if the model
// is a model resource ...
ModelResource result = (ModelResource)this.emfResourceToModelResource.get(resource);
if ( result == null ) {
// See if the resource's ResourceSet is the ModelerCore.getModelContainer();
ResourceSet resourceSet = resource.getResourceSet();
try {
Container container = null;
if ( resourceSet instanceof EmfResourceSet ) {
container = ((EmfResourceSet)resourceSet).getContainer();
} else if ( resource instanceof EmfResource ) {
container = ((EmfResource)resource).getContainer();
}
if ( container == null || container != ModelerCore.getModelContainer() ) {
// It isn't, so don't bother lookup up a ModelResource
return null;
}
resourceSet = container;
} catch (CoreException e2) {
// Couldn't get the ModelContainer, so just continue with the rest of the logic ...
ModelerCore.Util.log(e2);
}
// Didn't find a ModelResource in the map, so the resource must have
// been loaded because another (opened) model referenced it and somebody
// followed the reference to the (indirectly-loaded) resource.
// Get the URI of the resource ...
final URI resourceURI = resource.getURI();
String fileString = null;
if (resourceURI.isFile()) {
fileString = resourceURI.toFileString();
} else {
IResource iResource = WorkspaceResourceFinderUtil.findIResource(resourceURI);
if (iResource != null) {
fileString = iResource.getLocation().toOSString();
}
}
if ( fileString == null ) {
// The fileString may be of the form "platform:/resource/<path to workspace resource>".
// (This is the case with the XSD editor.)
// So, try letting the Eclipse platform resolve the URL ...
try {
final URL fileUrl = new URL(resourceURI.toString());
final URL resolvedFileUrl = FileLocator.resolve(fileUrl);
if ( resolvedFileUrl != null ) {
fileString = resolvedFileUrl.getFile();
}
} catch (MalformedURLException e1) {
//ModelerCore.Util.log(e1); // don't do anything and continue
} catch (IOException e1) {
ModelerCore.Util.log(e1); // just log and continue
}
}
if ( fileString == null ) {
// Try resolving the URI via the model container's URIConverter ...
final URI normalizedUri = resourceSet.getURIConverter().normalize(resourceURI);
if ( "file".equals(normalizedUri.scheme()) ) { //$NON-NLS-1$
fileString = normalizedUri.toFileString();
}
}
if ( fileString == null ) {
return null; // no point in continuing
}
// // Optimization for XSDs:
// if ( fileString.endsWith(".xsd") ) { //$NON-NLS-1$
// // XML Schemas do not have a corresponding ModelResource
// return null;
// }
final IPath path = new Path(fileString);
try {
if(ResourcesPlugin.getPlugin() == null) {
return null;
}
final IWorkspaceRoot wsRoot = ModelerCore.getWorkspace().getRoot();
IFile resourceFile = wsRoot.getFileForLocation(path);
// See if the path is absolute with respect to the workspace
if ( resourceFile == null ) {
resourceFile = wsRoot.getFile(path);
}
// If the resourceFile reference is null then a file with the
// specified path does not exist in the set of existing projects
if (resourceFile == null) {
return null;
}
final ModelWorkspaceManager mgr = ModelWorkspaceManager.getModelWorkspaceManager();
final ModelResource mResource = (ModelResource)mgr.findModelWorkspaceItem(resourceFile);
if ( mResource == null ) {
// The model must have been a model in the container that was outside the ModelWorkspace
return null;
}
mResource.open(null);
result = mResource;
} catch (Throwable e) {
ModelerCore.Util.log(e);
}
}
return result;
}
OverflowingLRUCache getOpenBufferCache() {
return openBuffers;
}
/**
* @see ModelBufferFactory#createBuffer(Openable)
*/
@Override
public ModelBuffer createBuffer( final Openable owner) throws ModelWorkspaceException {
CoreArgCheck.isInstanceOf(ModelWorkspaceItem.class,owner);
ModelWorkspaceItem item = (ModelWorkspaceItem)owner;
IResource resource = item.getResource();
ResourceSet emfResourceSet = this.resourceSetFinder.getResourceSet(resource);
final ModelBuffer buffer = new ModelBufferImpl(
resource instanceof IFile ? (IFile)resource : null,
owner, emfResourceSet,
item.isReadOnly());
return buffer;
}
/**
* Adds a buffer to the table of open buffers. This is generally called by the Openable implementation
* when it opens it's buffer.
*/
protected void addBuffer(final ModelBuffer buffer) {
openBuffers.put(buffer.getOwner(), buffer);
}
/**
* Returns the open buffer associated with the given owner,
* or <code>null</code> if the owner does not have an open
* buffer associated with it.
*/
public ModelBuffer getOpenBuffer(Openable owner) {
CoreArgCheck.isNotNull(owner);
return (ModelBuffer)openBuffers.get(owner);
}
/**
* Returns the default buffer factory.
*/
public ModelBufferFactory getDefaultBufferFactory() {
return this;
}
/**
* Returns an enumeration of all open buffers.
* <p>
* The <code>Enumeration</code> answered is thread safe.
*
* @see OverflowingLRUCache
* @return Enumeration of IBuffer
*/
public Iterator getOpenBuffers() {
synchronized (openBuffers) {
return new LinkedList(openBuffers.values()).iterator();
}
}
/**
* Removes a buffer from the table of open buffers.
*/
protected void removeBuffer(final ModelBuffer buffer) {
openBuffers.remove(buffer.getOwner());
}
public ResourceSetFinder getResourceSetFinder() {
return this.resourceSetFinder;
}
}