All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.xtext.java.resource.JavaResource Maven / Gradle / Ivy

/**
 * Copyright (c) 2015, 2020 itemis AG (http://www.itemis.eu) and others.
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * SPDX-License-Identifier: EPL-2.0
 */
package org.eclipse.xtext.java.resource;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Map;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jdt.internal.compiler.batch.CompilationUnit;
import org.eclipse.xtext.common.types.JvmDeclaredType;
import org.eclipse.xtext.common.types.JvmType;
import org.eclipse.xtext.common.types.access.IJavaSchemeUriResolver;
import org.eclipse.xtext.common.types.access.TypeResource;
import org.eclipse.xtext.common.types.access.impl.AbstractClassMirror;
import org.eclipse.xtext.common.types.access.impl.AbstractJvmTypeProvider;
import org.eclipse.xtext.common.types.access.impl.IndexedJvmTypeAccess;
import org.eclipse.xtext.common.types.access.impl.URIHelperConstants;
import org.eclipse.xtext.parser.IEncodingProvider;
import org.eclipse.xtext.resource.IFragmentProvider;
import org.eclipse.xtext.resource.ISynchronizable;
import org.eclipse.xtext.util.concurrent.IUnitOfWork;
import org.eclipse.xtext.xbase.lib.Exceptions;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure0;

import com.google.common.io.CharStreams;
import com.google.inject.Inject;
import com.google.inject.Provider;

public class JavaResource extends ResourceImpl implements IJavaSchemeUriResolver, ISynchronizable {
	public static class Factory implements Resource.Factory {
		@Inject
		private Provider resourceProvider;

		@Override
		public Resource createResource(URI uri) {
			JavaResource resource = resourceProvider.get();
			resource.setURI(uri);
			return resource;
		}
	}

	public static class JavaElementFragment {
		private URI uri;

		private int idx;

		public JavaElementFragment(URI uri) {
			this.uri = uri;
			this.idx = getMethodPartOffset(uri.fragment());
		}

		/**
		 * @return URI pointing to a type, which is the conatiner type in case of a fragment pointing to a method.
		 */
		public URI getTypeURI() {
			if (idx == -1) {
				return uri;
			} else {
				String f = uri.fragment();
				return uri.appendFragment(f.substring(0, idx));
			}
		}

		public boolean isMethodFragment() {
			return idx != -1;
		}

		protected int getMethodPartOffset(String string) {
			if (string.endsWith("()")) {
				return string.lastIndexOf('.');
			}
			return -1;
		}
	}

	public static class JavaFragmentProvider extends AbstractClassMirror {
		@Override
		protected String getTypeName() {
			throw new UnsupportedOperationException("not supported");
		}

		@Override
		protected String getTypeName(JvmType type) {
			return type.getQualifiedName('$');
		}

		@Override
		public void initialize(TypeResource typeResource) {
			throw new UnsupportedOperationException("not supported");
		}

		@Override
		public boolean isSealed() {
			return true;
		}
		
		@Override
		public URI getLocationURI(Resource resource) {
			return resource.getURI();
		}
	}

	public static final String OPTION_ENCODING = JavaResource.class.getName() + ".DEFAULT_ENCODING";

	@Inject
	private IEncodingProvider encodingProvider;

	@Inject
	private JavaDerivedStateComputer derivedStateComputer;

	private CompilationUnit compilationUnit;

	private String contentsAsString;

	@Override
	protected void doLoad(InputStream inputStream, Map options) throws IOException {
		String encoding = getEncoding(getURI(), options);
		InputStreamReader inputStreamReader = new InputStreamReader(inputStream, encoding);
		contentsAsString = CharStreams.toString(inputStreamReader);
		compilationUnit = new CompilationUnit(contentsAsString.toCharArray(), getURI().lastSegment(), encoding, null);
	}

	protected String getEncoding(URI uri, Map options) {
		if (options != null) {
			Object encodingOption = options.get(JavaResource.OPTION_ENCODING);
			if (encodingOption instanceof String) {
				return ((String) encodingOption);
			}
		}
		return encodingProvider.getEncoding(uri);
	}

	protected CompilationUnit getCompilationUnit() {
		return compilationUnit;
	}

	private boolean initialized = false;

	private boolean initializing = false;

	@Override
	public EList getContents() {
		synchronized (getLock()) {
			if (isLoaded && !isLoading && !initializing && !initialized) {
				try {
					eSetDeliver(false);
					installFull();
				} finally {
					eSetDeliver(true);
				}
			}
			return super.getContents();
		}
	}

	@Override
	protected List getUnloadingContents() {
		return super.getContents();
	}

	public void installStubs() {
		initializing(() -> {
			derivedStateComputer.installStubs(this);
			initialized = true;
		});
	}

	public void installFull() {
		initializing(() -> {
			derivedStateComputer.installFull(this);
			compilationUnit = null;
			initialized = true;
		});
	}

	private void initializing(Procedure0 init) {
		try {
			initializing = true;
			init.apply();
		} finally {
			initializing = false;
		}
	}

	public void discardDerivedState() {
		initializing(() -> {
			derivedStateComputer.discardDerivedState(this);
			initialized = false;
		});
	}

	@Override
	public EObject resolveJavaObjectURIProxy(InternalEObject proxy, EObject sender) {
		URI proxyURI = proxy.eProxyURI();
		if (proxyURI != null && URIHelperConstants.PROTOCOL.equals(proxyURI.scheme())) {
			if ("Objects".equals(proxyURI.segment(0))) {
				IndexedJvmTypeAccess access = getIndexJvmTypeAccess();
				if (access != null) {
					try {
						final JavaResource.JavaElementFragment frag = new JavaResource.JavaElementFragment(
								proxy.eProxyURI());
						EObject result = access.getIndexedJvmType(frag.getTypeURI(), this.getResourceSet());
						if (result instanceof JvmDeclaredType && frag.isMethodFragment()) {
							JavaResource.JavaFragmentProvider javaFragmentProvider = new JavaResource.JavaFragmentProvider();
							Resource res = result.eResource();
							result = javaFragmentProvider.getEObject(res, proxy.eProxyURI().fragment(),
									new IFragmentProvider.Fallback() {
										@Override
										public EObject getEObject(String fragment) {
											return null;
										}

										@Override
										public String getFragment(EObject obj) {
											return null;
										}
									});
						}
						if (result != null) {
							return result;
						}
					} catch (Throwable t) {
						if (t instanceof IndexedJvmTypeAccess.UnknownNestedTypeException) {
							return proxy;
						}
						throw Exceptions.sneakyThrow(t);
					}
				}
				return EcoreUtil.resolve(proxy, sender);
			}
		}
		return null;
	}

	private IndexedJvmTypeAccess indexedJvmTypeAccess;

	public IndexedJvmTypeAccess getIndexJvmTypeAccess() {
		if (indexedJvmTypeAccess == null) {
			Object provider = resourceSet.getResourceFactoryRegistry().getProtocolToFactoryMap()
					.get(URIHelperConstants.PROTOCOL);
			if (provider instanceof AbstractJvmTypeProvider) {
				indexedJvmTypeAccess = ((AbstractJvmTypeProvider) provider).getIndexedJvmTypeAccess();
			}
		}
		return indexedJvmTypeAccess;
	}

	/**
	 * Returns the lock of the owning {@link ResourceSet}, if it exposes such a lock. Otherwise this resource itself is
	 * used as the lock context.
	 */
	@Override
	public Object getLock() {
		ResourceSet resourceSet = getResourceSet();
		if (resourceSet instanceof ISynchronizable) {
			return ((ISynchronizable) resourceSet).getLock();
		}
		return this;
	}

	@Override
	public  Result execute(IUnitOfWork unit) throws Exception {
		synchronized (getLock()) {
			return unit.exec(this);
		}
	}

	private final IFragmentProvider.Fallback fallback = new IFragmentProvider.Fallback() {
		@Override
		public EObject getEObject(String fragment) {
			return JavaResource.super.getEObjectByID(fragment);
		}

		@Override
		public String getFragment(EObject obj) {
			return JavaResource.super.getURIFragment(obj);
		}
	};

	private final AbstractClassMirror m = new AbstractClassMirror() {
		@Override
		protected String getTypeName() {
			throw new UnsupportedOperationException("TODO: auto-generated method stub");
		}

		@Override
		protected String getTypeName(JvmType type) {
			return type.getIdentifier();
		}

		@Override
		public void initialize(TypeResource typeResource) {
			throw new UnsupportedOperationException("TODO: auto-generated method stub");
		}

		@Override
		public boolean isSealed() {
			throw new UnsupportedOperationException("TODO: auto-generated method stub");
		}
		
		@Override
		public URI getLocationURI(Resource resource) {
			return resource.getURI();
		}
	};

	@Override
	protected EObject getEObjectByID(String id) {
		return m.getEObject(this, id, fallback);
	}

	@Override
	public String getURIFragment(EObject eObject) {
		return m.getFragment(eObject, fallback);
	}

	public String getOriginalSource() {
		return contentsAsString;
	}

	public boolean isInitialized() {
		return initialized;
	}

	public boolean isInitializing() {
		return initializing;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy