| /** |
| * Copyright (c) 2011, 2015 - Lunifera GmbH (Gross Enzersdorf, Austria), Loetz GmbH&Co.KG (69115 Heidelberg, Germany) |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Florian Pirchner - Initial implementation |
| */ |
| package org.eclipse.osbp.xtext.builder.metadata.services.impl; |
| |
| import static com.google.common.collect.Iterables.addAll; |
| |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.Dictionary; |
| import java.util.Enumeration; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.osbp.dsl.xtext.types.bundles.BundleSpace; |
| import org.eclipse.osbp.dsl.xtext.types.bundles.BundleSpaceTypeProvider; |
| import org.eclipse.osbp.runtime.common.types.IBundleSpace; |
| import org.eclipse.osbp.xtext.builder.metadata.services.IBuilderParticipant; |
| import org.eclipse.osbp.xtext.builder.metadata.services.IMetadataBuilderService; |
| import org.eclipse.osbp.xtext.builder.metadata.services.IUnitOfWork; |
| import org.eclipse.xtext.common.types.JvmDeclaredType; |
| import org.eclipse.xtext.common.types.TypesPackage; |
| import org.eclipse.xtext.common.types.access.impl.IndexedJvmTypeAccess; |
| import org.eclipse.xtext.findReferences.IReferenceFinder; |
| import org.eclipse.xtext.findReferences.IReferenceFinder.Acceptor; |
| import org.eclipse.xtext.findReferences.ReferenceFinder; |
| import org.eclipse.xtext.findReferences.TargetURIs; |
| import org.eclipse.xtext.naming.IQualifiedNameConverter; |
| import org.eclipse.xtext.naming.QualifiedName; |
| import org.eclipse.xtext.resource.IEObjectDescription; |
| import org.eclipse.xtext.resource.IReferenceDescription; |
| import org.eclipse.xtext.resource.IResourceDescription; |
| import org.eclipse.xtext.resource.IResourceDescriptions; |
| import org.eclipse.xtext.resource.IResourceServiceProvider; |
| import org.eclipse.xtext.resource.ISelectable; |
| import org.eclipse.xtext.resource.XtextResourceSet; |
| import org.eclipse.xtext.resource.impl.ResourceDescriptionsData; |
| import org.eclipse.xtext.resource.impl.ResourceDescriptionsData.ResourceSetAdapter; |
| import org.eclipse.xtext.validation.CheckMode; |
| import org.eclipse.xtext.validation.IResourceValidator; |
| import org.eclipse.xtext.validation.Issue; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleEvent; |
| import org.osgi.framework.BundleListener; |
| import org.osgi.framework.FrameworkEvent; |
| import org.osgi.framework.FrameworkListener; |
| import org.osgi.framework.ServiceRegistration; |
| import org.osgi.service.component.ComponentContext; |
| import org.osgi.service.component.annotations.Activate; |
| import org.osgi.service.component.annotations.Component; |
| import org.osgi.service.component.annotations.Deactivate; |
| import org.osgi.service.component.annotations.Reference; |
| import org.osgi.service.component.annotations.ReferenceCardinality; |
| import org.osgi.service.component.annotations.ReferencePolicy; |
| import org.slf4j.Logger; |
| |
| import com.google.common.base.Function; |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Lists; |
| import com.google.inject.Guice; |
| import com.google.inject.Injector; |
| |
| // TODO: Auto-generated Javadoc |
| /** |
| * The Class MetadataBuilder. |
| * |
| * @author riegel |
| */ |
| @SuppressWarnings("restriction") |
| @Component(immediate = true, service = {}) |
| public class MetadataBuilder implements BundleListener { |
| |
| /** The Constant LOGGER. */ |
| private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(MetadataBuilder.class); |
| |
| // The service impl, which is being registered in the service registry |
| |
| /** The service impl. */ |
| private ServiceImpl serviceImpl; |
| |
| /** The context. */ |
| // Is used to sync calls to the bundle space |
| private ComponentContext context; |
| |
| /** The resource set. */ |
| private XtextResourceSet resourceSet; |
| |
| /** The index. */ |
| private ResourceDescriptionsData index; |
| |
| /** The grammar registry. */ |
| private IResourceServiceProvider.Registry grammarRegistry; |
| |
| /** The injector. */ |
| private Injector injector; |
| |
| /** The reference finder. */ |
| private ReferenceFinder referenceFinder; |
| |
| /** The converter. */ |
| private IQualifiedNameConverter converter; |
| |
| /** The jvm type access. */ |
| private IndexedJvmTypeAccess jvmTypeAccess; |
| |
| /** The bundle space. */ |
| private IBundleSpace bundleSpace; |
| |
| /** The type provider. */ |
| private BundleSpaceTypeProvider typeProvider; |
| |
| /** The model providers. */ |
| // participants |
| private Set<Bundle> modelProviders = Collections.synchronizedSet(new HashSet<Bundle>()); |
| |
| /** The participants. */ |
| private List<IBuilderParticipant> participants = Collections.synchronizedList(new ArrayList<IBuilderParticipant>()); |
| |
| /** The injected participants. */ |
| private Set<IBuilderParticipant> injectedParticipants = Collections |
| .synchronizedSet(new HashSet<IBuilderParticipant>()); |
| |
| /** The waiting for framework started event. */ |
| // lifecycle |
| private AtomicBoolean waitingForFrameworkStartedEvent = new AtomicBoolean(true); |
| |
| /** The resolved. */ |
| private AtomicBoolean resolved = new AtomicBoolean(false); |
| |
| /** The bundle space reg. */ |
| // service registrations |
| private ServiceRegistration<IBundleSpace> bundleSpaceReg; |
| |
| /** The service impl reg. */ |
| private ServiceRegistration<IMetadataBuilderService> serviceImplReg; |
| |
| /** |
| * Activate. |
| * |
| * @param context |
| * the context |
| */ |
| @Activate |
| public synchronized void activate(ComponentContext context) { |
| this.context = context; |
| this.serviceImpl = new ServiceImpl(); |
| |
| new ServiceActivatedTask().run(); |
| } |
| |
| /** |
| * Checks if is active. |
| * |
| * @return true, if is active |
| */ |
| private boolean isActive() { |
| return context != null; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Deactivate |
| public synchronized void deactivate() { |
| new ServiceDeactivatedTask().run(); |
| this.context = null; |
| } |
| |
| /** |
| * Returns the eObject for the given fully qualified name and type. |
| * |
| * @param fqn |
| * the fqn |
| * @param type |
| * the type |
| * @return the e object for FQN |
| */ |
| public EObject getEObjectForFQN(QualifiedName fqn, EClass type) { |
| EObject result = null; |
| ISelectable resourceDescriptions = ResourceDescriptionsData.ResourceSetAdapter |
| .findResourceDescriptionsData(resourceSet); |
| Iterable<IEObjectDescription> descriptions = resourceDescriptions.getExportedObjects(type, fqn, false); |
| for (IEObjectDescription desc : descriptions) { |
| result = desc.getEObjectOrProxy(); |
| if (result.eIsProxy()) { |
| result = EcoreUtil.resolve(result, resourceSet); |
| } |
| break; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Returns true, if the bundle contains the header. |
| * |
| * @param bundle |
| * the bundle |
| * @param header |
| * the header |
| * @return true, if successful |
| */ |
| private boolean containsHeader(Bundle bundle, String header) { |
| Dictionary<String, String> headers = bundle.getHeaders(); |
| Enumeration<String> keys = headers.keys(); |
| while (keys.hasMoreElements()) { |
| String key = keys.nextElement(); |
| if (key.equals(header)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Activates the given participant. |
| * |
| * @param participant |
| * the participant |
| */ |
| private void doNotifyParticipantActivate(IBuilderParticipant participant) { |
| if (isActive()) { |
| // Tell the participant to activate its state |
| participant.notifyLifecyle( |
| new IBuilderParticipant.LifecycleEvent(IBuilderParticipant.LifecycleEvent.ACTIVATED)); |
| } |
| } |
| |
| /** |
| * Do notify participant bundles scanned. |
| * |
| * @param participant |
| * the participant |
| */ |
| private void doNotifyParticipantBundlesScanned(IBuilderParticipant participant) { |
| if (isActive()) { |
| // Tell the participant to activate its state |
| participant.notifyLifecyle( |
| new IBuilderParticipant.LifecycleEvent(IBuilderParticipant.LifecycleEvent.BUNDLES_SCANNED)); |
| } |
| } |
| |
| /** |
| * Removes the models contained in the given bundle from the index. |
| * |
| * @param bundle |
| * the bundle |
| */ |
| private void removeFromIndex(Bundle bundle) { |
| if (!isActive()) { |
| return; |
| } |
| List<URL> urls = doFindModels(bundle); |
| if (urls.isEmpty()) { |
| return; |
| } |
| |
| removeFromIndex(urls); |
| } |
| |
| /** |
| * Removes the models contained in the given bundle from the index. |
| * |
| * @param participant |
| * the participant |
| */ |
| private void removeFromIndex(IBuilderParticipant participant) { |
| if (!resolved.get()) { |
| return; |
| } |
| List<URL> urls = doFindAllModelsToRemoveForParticipant(participant); |
| if (urls.isEmpty()) { |
| return; |
| } |
| |
| removeFromIndex(urls); |
| } |
| |
| /** |
| * Validate. |
| * |
| * @param resourceSet |
| * the resource set |
| * @return the list |
| */ |
| protected List<Issue> validate(ResourceSet resourceSet) { |
| if (resourceSet.getResources() == null) { |
| return Collections.emptyList(); |
| } |
| List<Issue> issues = Lists.newArrayList(); |
| List<Resource> resources = Lists.newArrayList(resourceSet.getResources()); |
| for (Resource resource : resources) { |
| IResourceServiceProvider resourceServiceProvider = IResourceServiceProvider.Registry.INSTANCE |
| .getResourceServiceProvider(resource.getURI()); |
| if (resourceServiceProvider != null) { |
| IResourceValidator resourceValidator = resourceServiceProvider.getResourceValidator(); |
| List<Issue> result = resourceValidator.validate(resource, CheckMode.ALL, null); |
| addAll(issues, result); |
| } |
| } |
| return issues; |
| } |
| |
| /** |
| * Looks up for all models available. |
| * |
| * @param suspect |
| * the suspect |
| * @return the list |
| */ |
| private List<URL> doFindModels(Bundle suspect) { |
| |
| List<URL> result = new ArrayList<URL>(); |
| // iterate all participants |
| synchronized (participants) { |
| for (IBuilderParticipant participant : participants) { |
| result.addAll(doFindModels(suspect, participant)); |
| } |
| } |
| |
| if (result.size() > 0) { |
| modelProviders.add(suspect); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Returns all models for the given bundle and participant. |
| * |
| * @param suspect |
| * the suspect |
| * @param participant |
| * the participant |
| * @return the list |
| */ |
| private List<URL> doFindModels(Bundle suspect, IBuilderParticipant participant) { |
| return participant.getModels(suspect); |
| } |
| |
| /** |
| * Returns all models for the given participant. Therefore <b>only known |
| * model provider bundles</b> are used. |
| * |
| * @param participant |
| * the participant |
| * @return the list |
| */ |
| private List<URL> doFindAllModelsToRemoveForParticipant(IBuilderParticipant participant) { |
| |
| List<URL> result = new ArrayList<URL>(); |
| synchronized (modelProviders) { |
| for (Bundle bundle : modelProviders) { |
| result.addAll(doFindModels(bundle, participant)); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Returns all models for the given participant. Therefore <b>ALL</b> |
| * bundles are used. |
| * |
| * @param participant |
| * the participant |
| * @return the list |
| */ |
| private List<URL> doFindAllModelsForNewParticipant(IBuilderParticipant participant) { |
| |
| List<URL> result = new ArrayList<URL>(); |
| for (Bundle bundle : context.getBundleContext().getBundles()) { |
| |
| List<URL> temp = doFindModels(bundle, participant); |
| if (temp.size() > 0) { |
| doAddToBundleSpace(bundle); |
| modelProviders.add(bundle); |
| } |
| |
| result.addAll(temp); |
| } |
| |
| return result; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.osgi.framework.BundleListener#bundleChanged(org.osgi.framework. |
| * BundleEvent) |
| */ |
| @Override |
| public synchronized void bundleChanged(BundleEvent event) { |
| if (event.getType() == BundleEvent.STARTED) { |
| new BundleAddedTask(event.getBundle()).run(); |
| } else if (event.getType() == BundleEvent.STOPPED) { |
| new BundleRemovedTask(event.getBundle()).run(); |
| } |
| } |
| |
| /** |
| * Called by OSGi-DS. |
| * |
| * @param participant |
| * the participant |
| */ |
| @Reference(cardinality = ReferenceCardinality.AT_LEAST_ONE, policy = ReferencePolicy.DYNAMIC, unbind = "removeParticipant") |
| public synchronized void addParticipant(IBuilderParticipant participant) { |
| try { |
| new ParticipantAddedTask(participant).run(); |
| } catch (Exception ex) { |
| LOGGER.error("{}", ex); |
| } |
| } |
| |
| /** |
| * Resolves all models for all proper model bundles. |
| */ |
| private void doScanAllBundles() { |
| |
| List<String> urls = new ArrayList<>(); |
| for (Bundle bundle : context.getBundleContext().getBundles()) { |
| if (bundle.getState() <= 2) { |
| continue; |
| } |
| if (containsHeader(bundle, IMetadataBuilderService.LUN_RUNTIME_BUILDER_BUNDLE_SPACE)) { |
| doAddToBundleSpace(bundle); |
| } |
| for (URL url : doFindModels(bundle)) { |
| LOGGER.info("Adding model " + url.toString() + " to model index."); |
| if (filter(url)) { |
| continue; |
| } |
| |
| urls.add(url.toString()); |
| |
| // adds the bundle to the bundleSpace if header is available |
| doAddToBundleSpace(bundle); |
| } |
| } |
| |
| /* |
| * due to a bug in org.eclipse.bpmn2 the Bpmn2OppositeReferenceAdapter |
| * is an EContentAdapter and attached to every mode element in the |
| * resource set. Causing every resource to become loaded too early. |
| * Therefore we sort bpmn2 extensions to the end of the loading list. |
| */ |
| Collections.sort(urls, new Comparator<String>() { |
| |
| @Override |
| public int compare(String o1, String o2) { |
| URI uri1 = URI.createURI(o1); |
| URI uri2 = URI.createURI(o2); |
| |
| String e1 = uri1.fileExtension(); |
| String e2 = uri2.fileExtension(); |
| |
| if (e2.equals("bpmn2")) { |
| return -1; |
| } |
| |
| if (e1.equals("bpmn2")) { |
| return 1; |
| } |
| |
| return e1.compareTo(e2); |
| } |
| }); |
| |
| for (String url : urls) { |
| addToIndex(URI.createURI(url), true); |
| } |
| |
| LOGGER.info("Models indexed. In case of error, see messages before."); |
| } |
| |
| /** |
| * Unloads all resources in the resource set. |
| */ |
| private void doUnloadAllResources() { |
| for (Resource resource : new ArrayList<>(resourceSet.getResources())) { |
| if (!resource.getURI().scheme().equals("java")) { |
| resource.unload(); |
| } |
| } |
| |
| LOGGER.info("Unloaded all resources."); |
| } |
| |
| /** |
| * Filter. |
| * |
| * @param url |
| * the url |
| * @return true, if successful |
| */ |
| private boolean filter(URL url) { |
| if (url.toExternalForm().contains("META-INF/maven")) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Resolves all models for the given participant. Therefore <b>all |
| * bundles</b> are used. |
| * |
| * @param participant |
| * the participant |
| */ |
| private void doScanAllBundles(IBuilderParticipant participant) { |
| for (URL url : doFindAllModelsForNewParticipant(participant)) { |
| if (filter(url)) { |
| continue; |
| } |
| |
| LOGGER.info("Adding model " + url.toString() + " to model index."); |
| addToIndex(URI.createURI(url.toString()), true); |
| } |
| |
| LOGGER.info("Models indexed. In case of error, see messages before."); |
| } |
| |
| /** |
| * Do notify participants bundles scanned. |
| */ |
| private void doNotifyParticipantsBundlesScanned() { |
| synchronized (participants) { |
| for (IBuilderParticipant participant : participants) { |
| doNotifyParticipantBundlesScanned(participant); |
| } |
| } |
| } |
| |
| /** |
| * Do notify participant initialize. |
| * |
| * @param participant |
| * the participant |
| */ |
| private void doNotifyParticipantInitialize(IBuilderParticipant participant) { |
| participant |
| .notifyLifecyle(new IBuilderParticipant.LifecycleEvent(IBuilderParticipant.LifecycleEvent.INITIALIZE)); |
| } |
| |
| /** |
| * Do inject participant. |
| * |
| * @param participant |
| * the participant |
| */ |
| private void doInjectParticipant(IBuilderParticipant participant) { |
| if (isActive() && !injectedParticipants.contains(participant)) { |
| injector.injectMembers(participant); |
| injectedParticipants.add(participant); |
| } |
| } |
| |
| /** |
| * Handle task finish. |
| * |
| * @param task |
| * the task |
| */ |
| protected void handleTaskFinish(ITask task) { |
| if (task.getClass() == ServiceActivatedTask.class) { |
| new WaitForFrameworkTask().run(); |
| } else if (task.getClass() == WaitForFrameworkTask.class) { |
| new InitialIndexingTask().run(); |
| } else if (task.getClass() == InitialIndexingTask.class) { |
| registerOSGiService(); |
| // nothing to do for now. All listeners are installed properly |
| } |
| } |
| |
| /** |
| * Register the service impl as an OSGi service. |
| */ |
| private void registerOSGiService() { |
| serviceImplReg = context.getBundleContext().registerService(IMetadataBuilderService.class, serviceImpl, null); |
| } |
| |
| /** |
| * Called by OSGi-DS. |
| * |
| * @param participant |
| * the participant |
| */ |
| public synchronized void removeParticipant(IBuilderParticipant participant) { |
| try { |
| new ParticipantRemovedTask(participant).run(); |
| } catch (Exception ex) { |
| LOGGER.error("{}", ex); |
| } |
| } |
| |
| /** |
| * Do deactivate participant. |
| * |
| * @param participant |
| * the participant |
| */ |
| private void doDeactivateParticipant(IBuilderParticipant participant) { |
| |
| // remove all models for the given participant from the index |
| removeFromIndex(participant); |
| |
| participants.remove(participant); |
| injectedParticipants.remove(participant); |
| |
| // tell the participant to deactivate |
| participant |
| .notifyLifecyle(new IBuilderParticipant.LifecycleEvent(IBuilderParticipant.LifecycleEvent.DEACTIVATED)); |
| |
| } |
| |
| /** |
| * Adds the bundle to the bundle space if the header is available. |
| * |
| * @param bundle |
| * the bundle |
| */ |
| private void doAddToBundleSpace(Bundle bundle) { |
| synchronized (bundleSpace) { |
| bundleSpace.add(bundle); |
| } |
| } |
| |
| /** |
| * Removes the given bundle from the bundle space. |
| * |
| * @param bundle |
| * the bundle |
| */ |
| private void doRemoveFromBundleSpace(Bundle bundle) { |
| synchronized (bundleSpace) { |
| bundleSpace.remove(bundle); |
| } |
| } |
| |
| /** |
| * Adds the to index. |
| * |
| * @param uri |
| * the uri |
| * @param load |
| * TODO |
| */ |
| protected void addToIndex(URI uri, boolean load) { |
| Resource resource = resourceSet.getResource(uri, load); |
| if (resource.isLoaded()) { |
| |
| IResourceDescription.Manager manager = grammarRegistry.getResourceServiceProvider(uri) |
| .get(IResourceDescription.Manager.class); |
| try { |
| index.addDescription(uri, manager.getResourceDescription(resource)); |
| } catch (Exception ex) { |
| LOGGER.error("Exception adding " + uri + " to index. See: {}", ex); |
| } |
| |
| // unload the resource again |
| resource.unload(); |
| } |
| } |
| |
| /** |
| * Removes the given URLs from the index. |
| * |
| * @param urls |
| * the urls |
| */ |
| protected void removeFromIndex(List<URL> urls) { |
| if (!isActive()) { |
| return; |
| } |
| |
| for (URL url : urls) { |
| if (filter(url)) { |
| continue; |
| } |
| |
| LOGGER.info("Unregistered " + url.toString()); |
| removeFromIndex(URI.createURI(url.toString())); |
| } |
| } |
| |
| /** |
| * Removes the from index. |
| * |
| * @param uri |
| * the uri |
| */ |
| protected void removeFromIndex(URI uri) { |
| index.removeDescription(uri); |
| } |
| |
| /** |
| * An internal task that processes different kinds of issues. |
| */ |
| interface ITask { |
| |
| /** |
| * Run. |
| */ |
| void run(); |
| } |
| |
| /** |
| * This task handles waiting for the framework start. Only if the framework |
| * became started, the models may become indexed. |
| */ |
| private class WaitForFrameworkTask implements ITask, FrameworkListener { |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.osbp.xtext.builder.metadata.services.impl.MetadataBuilder |
| * .ITask#run() |
| */ |
| @Override |
| public void run() { |
| |
| // get the state of the framework |
| Bundle framework = context.getBundleContext().getBundle(0); |
| if (framework.getState() == Bundle.ACTIVE) { |
| waitingForFrameworkStartedEvent.set(false); |
| } |
| |
| if (waitingForFrameworkStartedEvent.get()) { |
| context.getBundleContext().addFrameworkListener(this); |
| } else { |
| notifyFrameworkStarted(); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.osgi.framework.FrameworkListener#frameworkEvent(org.osgi. |
| * framework.FrameworkEvent) |
| */ |
| @Override |
| public void frameworkEvent(FrameworkEvent event) { |
| if (event.getType() == FrameworkEvent.STARTED) { |
| context.getBundleContext().removeFrameworkListener(this); |
| |
| notifyFrameworkStarted(); |
| } |
| } |
| |
| /** |
| * Notify framework started. |
| */ |
| private void notifyFrameworkStarted() { |
| waitingForFrameworkStartedEvent.set(false); |
| |
| handleTaskFinish(this); |
| } |
| } |
| |
| /** |
| * This task will be called, if the service service was activated. |
| */ |
| private class ServiceActivatedTask implements ITask { |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.osbp.xtext.builder.metadata.services.impl.MetadataBuilder |
| * .ITask#run() |
| */ |
| @Override |
| public void run() { |
| doSetupService(); |
| doInjectParticipants(); |
| doInitializeParticipants(); |
| doActivateParticipants(); |
| |
| handleTaskFinish(this); |
| } |
| |
| /** |
| * Does the setup. |
| */ |
| protected void doSetupService() { |
| injector = Guice.createInjector(new MetadataBuilderModule(serviceImpl)); |
| converter = injector.getInstance(IQualifiedNameConverter.class); |
| resourceSet = injector.getInstance(XtextResourceSet.class); |
| index = new ResourceDescriptionsData(new ArrayList<IResourceDescription>()); |
| ResourceDescriptionsData.ResourceSetAdapter.installResourceDescriptionsData(resourceSet, index); |
| grammarRegistry = injector.getInstance(IResourceServiceProvider.Registry.class); |
| |
| jvmTypeAccess = injector.getInstance(IndexedJvmTypeAccess.class); |
| bundleSpace = injector.getInstance(BundleSpace.class); |
| |
| referenceFinder = injector.getInstance(ReferenceFinder.class); |
| |
| // register the bundle space |
| bundleSpaceReg = context.getBundleContext().registerService(IBundleSpace.class, bundleSpace, null); |
| |
| bundleSpace.add(context.getBundleContext().getBundle()); |
| |
| // Create the bundle space for class loading issues |
| typeProvider = new BundleSpaceTypeProvider(bundleSpace, resourceSet, jvmTypeAccess); |
| resourceSet.setClasspathURIContext(bundleSpace); |
| } |
| |
| /** |
| * Do initialize participants. |
| */ |
| private void doInitializeParticipants() { |
| for (IBuilderParticipant participant : participants.toArray(new IBuilderParticipant[participants.size()])) { |
| doNotifyParticipantInitialize(participant); |
| } |
| } |
| |
| /** |
| * Do inject participants. |
| */ |
| private void doInjectParticipants() { |
| for (IBuilderParticipant participant : participants) { |
| doInjectParticipant(participant); |
| } |
| } |
| |
| /** |
| * Activate all participants. |
| */ |
| private void doActivateParticipants() { |
| for (IBuilderParticipant participant : participants.toArray(new IBuilderParticipant[participants.size()])) { |
| doNotifyParticipantActivate(participant); |
| } |
| } |
| } |
| |
| /** |
| * The Class InitialIndexingTask. |
| */ |
| private class InitialIndexingTask implements ITask { |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.osbp.xtext.builder.metadata.services.impl.MetadataBuilder |
| * .ITask#run() |
| */ |
| @Override |
| public void run() { |
| doScanAllBundles(); |
| |
| doUnloadAllResources(); |
| |
| doNotifyParticipantsBundlesScanned(); |
| |
| startBundleTracking(); |
| |
| resolved.set(true); |
| |
| handleTaskFinish(this); |
| } |
| |
| /** |
| * Starts the tracking of bundles. |
| */ |
| private synchronized void startBundleTracking() { |
| context.getBundleContext().addBundleListener(MetadataBuilder.this); |
| } |
| |
| } |
| |
| /** |
| * The Class AddBundleToBundleSpaceTask. |
| */ |
| private class AddBundleToBundleSpaceTask implements ITask { |
| |
| /** The bundle. */ |
| private final Bundle bundle; |
| |
| /** |
| * Instantiates a new adds the bundle to bundle space task. |
| * |
| * @param bundle |
| * the bundle |
| */ |
| public AddBundleToBundleSpaceTask(Bundle bundle) { |
| this.bundle = bundle; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.osbp.xtext.builder.metadata.services.impl.MetadataBuilder |
| * .ITask#run() |
| */ |
| @Override |
| public void run() { |
| doAddToBundleSpace(bundle); |
| } |
| } |
| |
| /** |
| * The Class RemoveBundleFromBundleSpaceTask. |
| */ |
| private class RemoveBundleFromBundleSpaceTask implements ITask { |
| |
| /** The bundle. */ |
| private final Bundle bundle; |
| |
| /** |
| * Instantiates a new removes the bundle from bundle space task. |
| * |
| * @param bundle |
| * the bundle |
| */ |
| public RemoveBundleFromBundleSpaceTask(Bundle bundle) { |
| this.bundle = bundle; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.osbp.xtext.builder.metadata.services.impl.MetadataBuilder |
| * .ITask#run() |
| */ |
| @Override |
| public void run() { |
| doRemoveFromBundleSpace(bundle); |
| } |
| |
| } |
| |
| /** |
| * The Class BundleAddedTask. |
| */ |
| private class BundleAddedTask implements ITask { |
| |
| /** The bundle. */ |
| private final Bundle bundle; |
| |
| /** |
| * Instantiates a new bundle added task. |
| * |
| * @param bundle |
| * the bundle |
| */ |
| public BundleAddedTask(Bundle bundle) { |
| this.bundle = bundle; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.osbp.xtext.builder.metadata.services.impl.MetadataBuilder |
| * .ITask#run() |
| */ |
| @Override |
| public void run() { |
| // started bundles need to expose the MANIFEST header |
| if (containsHeader(bundle, IMetadataBuilderService.LUN_RUNTIME_BUILDER_BUNDLE_SPACE)) { |
| doAddToBundleSpace(bundle); |
| } |
| |
| // if the bundle was not scanned yet |
| if (!modelProviders.contains(bundle)) { |
| doIndexAddedBundle(bundle); |
| } |
| } |
| |
| /** |
| * Indexes the models contained in the given bundle. |
| * |
| * @param bundle |
| * the bundle |
| */ |
| private synchronized void doIndexAddedBundle(Bundle bundle) { |
| List<URL> urls = doFindModels(bundle); |
| if (urls.isEmpty()) { |
| return; |
| } |
| for (URL url : urls) { |
| LOGGER.info("Added " + url.toString() + " to metadata cache."); |
| addToIndex(URI.createURI(url.toString()), true); |
| } |
| } |
| } |
| |
| /** |
| * The Class BundleRemovedTask. |
| */ |
| private class BundleRemovedTask implements ITask { |
| |
| /** The bundle. */ |
| private final Bundle bundle; |
| |
| /** |
| * Instantiates a new bundle removed task. |
| * |
| * @param bundle |
| * the bundle |
| */ |
| public BundleRemovedTask(Bundle bundle) { |
| this.bundle = bundle; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.osbp.xtext.builder.metadata.services.impl.MetadataBuilder |
| * .ITask#run() |
| */ |
| @Override |
| public void run() { |
| if (!isActive()) { |
| return; |
| } |
| |
| // remove the bundle from the bundle space |
| serviceImpl.removeFromBundleSpace(bundle); |
| |
| // the bundle was already scanned |
| if (!modelProviders.contains(bundle)) { |
| return; |
| } |
| |
| removeFromIndex(bundle); |
| |
| modelProviders.remove(bundle); |
| } |
| |
| } |
| |
| /** |
| * The Class ServiceDeactivatedTask. |
| */ |
| private class ServiceDeactivatedTask implements ITask { |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.osbp.xtext.builder.metadata.services.impl.MetadataBuilder |
| * .ITask#run() |
| */ |
| @Override |
| public void run() { |
| |
| if (bundleSpaceReg != null) { |
| bundleSpaceReg.unregister(); |
| bundleSpaceReg = null; |
| } |
| |
| if (serviceImplReg != null) { |
| serviceImplReg.unregister(); |
| serviceImplReg = null; |
| } |
| |
| context.getBundleContext().removeBundleListener(MetadataBuilder.this); |
| |
| modelProviders.clear(); |
| |
| serviceImpl = null; |
| resourceSet = null; |
| index = null; |
| grammarRegistry = null; |
| resolved.set(false); |
| } |
| } |
| |
| /** |
| * The Class ParticipantAddedTask. |
| */ |
| private class ParticipantAddedTask implements ITask { |
| |
| /** The participant. */ |
| private final IBuilderParticipant participant; |
| |
| /** |
| * Instantiates a new participant added task. |
| * |
| * @param participant |
| * the participant |
| */ |
| public ParticipantAddedTask(IBuilderParticipant participant) { |
| this.participant = participant; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.osbp.xtext.builder.metadata.services.impl.MetadataBuilder |
| * .ITask#run() |
| */ |
| @Override |
| public void run() { |
| if (!participants.contains(participant)) { |
| doInjectParticipant(participant); |
| |
| participants.add(participant); |
| |
| if (isActive()) { |
| // activate the participant |
| doNotifyParticipantInitialize(participant); |
| |
| // activate the participant |
| doNotifyParticipantActivate(participant); |
| |
| // scan all bundles to find proper models |
| doScanAllBundles(participant); |
| |
| doNotifyParticipantBundlesScanned(participant); |
| } |
| } |
| } |
| |
| } |
| |
| /** |
| * The Class ParticipantRemovedTask. |
| */ |
| private class ParticipantRemovedTask implements ITask { |
| |
| /** The participant. */ |
| private final IBuilderParticipant participant; |
| |
| /** |
| * Instantiates a new participant removed task. |
| * |
| * @param participant |
| * the participant |
| */ |
| public ParticipantRemovedTask(IBuilderParticipant participant) { |
| this.participant = participant; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.osbp.xtext.builder.metadata.services.impl.MetadataBuilder |
| * .ITask#run() |
| */ |
| @Override |
| public void run() { |
| doDeactivateParticipant(participant); |
| } |
| |
| } |
| |
| /** |
| * This service is immediatelly available for participants by @Inject |
| * IMetadataBuilderService. But it won't become registered as an OSGi |
| * service, before the models became resolved. |
| */ |
| public class ServiceImpl implements IMetadataBuilderService { |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.osbp.xtext.builder.metadata.services. |
| * IMetadataBuilderService#getAllDescriptions(org.eclipse.emf.ecore. |
| * EClass) |
| */ |
| @Override |
| public Iterable<IEObjectDescription> getAllDescriptions(EClass type) { |
| ISelectable resourceDescriptions = ResourceDescriptionsData.ResourceSetAdapter |
| .findResourceDescriptionsData(resourceSet); |
| Iterable<IEObjectDescription> descriptions = resourceDescriptions.getExportedObjectsByType(type); |
| return descriptions; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.osbp.xtext.builder.metadata.services. |
| * IMetadataBuilderService#addToBundleSpace(org.osgi.framework.Bundle) |
| */ |
| @Override |
| public synchronized void addToBundleSpace(Bundle bundle) { |
| new AddBundleToBundleSpaceTask(bundle).run(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.osbp.xtext.builder.metadata.services. |
| * IMetadataBuilderService#removeFromBundleSpace(org.osgi.framework. |
| * Bundle) |
| */ |
| @Override |
| public synchronized void removeFromBundleSpace(Bundle bundle) { |
| new RemoveBundleFromBundleSpaceTask(bundle).run(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.osbp.xtext.builder.metadata.services. |
| * IMetadataBuilderService#getAll(org.eclipse.emf.ecore.EClass) |
| */ |
| @Override |
| public Iterable<EObject> getAll(EClass eClass) { |
| return Iterables.transform(getAllDescriptions(eClass), new Function<IEObjectDescription, EObject>() { |
| @Override |
| public EObject apply(IEObjectDescription desc) { |
| EObject result = desc.getEObjectOrProxy(); |
| // TODO goingEclipse - maybe we should remove |
| // resolving here. See IUnitOfWork.GetAllUnitOfWork |
| return resolve(result); |
| } |
| }); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.osbp.xtext.builder.metadata.services. |
| * IMetadataBuilderService#resolve(org.eclipse.emf.ecore.EObject) |
| */ |
| @Override |
| public EObject resolve(EObject proxy) { |
| // TODO goingEclipse - maybe we should remove |
| // resolving here. See IUnitOfWork.ResolveUnitOfWork |
| return proxy.eIsProxy() ? EcoreUtil.resolve(proxy, resourceSet) : proxy; |
| } |
| |
| /** |
| * Returns the metadata model element for the given parameters. Or |
| * <code>null</code> if no model could be found. |
| * |
| * @param qualifiedName |
| * the qualified name |
| * @param type |
| * the type |
| * @return the metadata |
| */ |
| public EObject getMetadata(String qualifiedName, EClass type) { |
| return getEObjectForFQN(converter.toQualifiedName(qualifiedName), type); |
| } |
| |
| /** |
| * Gets the bundle space. |
| * |
| * @return the bundleSpace |
| */ |
| public IBundleSpace getBundleSpace() { |
| return bundleSpace; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.osbp.xtext.builder.metadata.services. |
| * IMetadataBuilderService#execute(java.lang.Object, |
| * org.eclipse.osbp.xtext.builder.metadata.services.IUnitOfWork) |
| */ |
| @Override |
| public <T> void execute(T state, IUnitOfWork<T> unitOfWork) { |
| try { |
| unitOfWork.exec(this, state); |
| } catch (Exception e) { |
| LOGGER.error("{}", e); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.osbp.xtext.builder.metadata.services. |
| * IMetadataBuilderService#getResourceSet() |
| */ |
| @Override |
| public XtextResourceSet getResourceSet() { |
| return resourceSet; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.osbp.xtext.builder.metadata.services. |
| * IMetadataBuilderService#findSubTypes(org.eclipse.xtext.common.types. |
| * JvmDeclaredType) |
| */ |
| @Override |
| public Set<JvmDeclaredType> findSubTypes(JvmDeclaredType type) { |
| Set<JvmDeclaredType> result = new HashSet<>(); |
| TargetURIs jvmTypeURIs = injector.getInstance(TargetURIs.class); |
| jvmTypeURIs.addURI(EcoreUtil.getURI(type)); |
| Acceptor acceptor = new Acceptor() { |
| |
| @Override |
| public void accept(EObject source, URI sourceURI, EReference eReference, int index, |
| EObject targetOrProxy, URI targetURI) { |
| if (eReference == TypesPackage.Literals.JVM_PARAMETERIZED_TYPE_REFERENCE__TYPE) { |
| if (sourceURI.fragment().endsWith("/@superTypes.0")) { |
| addToResult(sourceURI); |
| } |
| } |
| } |
| |
| @Override |
| public void accept(IReferenceDescription description) { |
| if (description.getEReference() == TypesPackage.Literals.JVM_PARAMETERIZED_TYPE_REFERENCE__TYPE) { |
| if (description.getSourceEObjectUri().fragment().endsWith("/@superTypes.0")) { |
| addToResult(description.getSourceEObjectUri()); |
| } |
| } |
| } |
| |
| private void addToResult(URI sourceURI) { |
| URI uri = URI.createURI(sourceURI.toString().replace("/@superTypes.0", "")); |
| result.add((JvmDeclaredType) resourceSet.getEObject(uri, true)); |
| } |
| }; |
| referenceFinder.findAllReferences(jvmTypeURIs, new LocalResourceAccess(resourceSet), |
| new DescriptionsWrapper(ResourceSetAdapter.findResourceDescriptionsData(resourceSet)), acceptor, |
| null); |
| |
| return result; |
| } |
| |
| @Override |
| /** |
| * Gets the bundle space type provider. |
| * |
| * @return the type provider |
| */ |
| public BundleSpaceTypeProvider getTypeProvider() { |
| return typeProvider; |
| } |
| |
| @Override |
| public void unloadResource(String extension) { |
| // selected filtered resources |
| List<Resource> filtered = new ArrayList<>(); |
| List<Resource> resources = new ArrayList<>(getResourceSet().getResources()); |
| for (Resource resource : resources) { |
| if(resource.getURI().lastSegment().contains(extension)) { |
| filtered.add(resource); |
| } |
| } |
| execute(null, new IUnitOfWork<Void>() { |
| @Override |
| public void exec(IMetadataBuilderService service, Void state) |
| throws Exception { |
| for (Resource resource : filtered) { |
| resource.unload(); |
| } |
| } |
| }); |
| } |
| } |
| |
| /** |
| * The Class DescriptionsWrapper. |
| */ |
| public static class DescriptionsWrapper implements IResourceDescriptions { |
| |
| /** The data. */ |
| private final ResourceDescriptionsData data; |
| |
| /** |
| * Instantiates a new descriptions wrapper. |
| * |
| * @param data |
| * the data |
| */ |
| public DescriptionsWrapper(ResourceDescriptionsData data) { |
| this.data = data; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.xtext.resource.ISelectable#isEmpty() |
| */ |
| @Override |
| public boolean isEmpty() { |
| return data.isEmpty(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.xtext.resource.ISelectable#getExportedObjects() |
| */ |
| @Override |
| public Iterable<IEObjectDescription> getExportedObjects() { |
| return data.getExportedObjects(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.xtext.resource.ISelectable#getExportedObjects(org.eclipse |
| * .emf.ecore.EClass, org.eclipse.xtext.naming.QualifiedName, boolean) |
| */ |
| @Override |
| public Iterable<IEObjectDescription> getExportedObjects(EClass type, QualifiedName name, boolean ignoreCase) { |
| return data.getExportedObjects(type, name, ignoreCase); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.xtext.resource.ISelectable#getExportedObjectsByType(org. |
| * eclipse.emf.ecore.EClass) |
| */ |
| @Override |
| public Iterable<IEObjectDescription> getExportedObjectsByType(EClass type) { |
| return data.getExportedObjectsByType(type); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.xtext.resource.ISelectable#getExportedObjectsByObject(org |
| * .eclipse.emf.ecore.EObject) |
| */ |
| @Override |
| public Iterable<IEObjectDescription> getExportedObjectsByObject(EObject object) { |
| return data.getExportedObjectsByObject(object); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.xtext.resource.IResourceDescriptions# |
| * getAllResourceDescriptions() |
| */ |
| @Override |
| public Iterable<IResourceDescription> getAllResourceDescriptions() { |
| return data.getAllResourceDescriptions(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.xtext.resource.IResourceDescriptions# |
| * getResourceDescription(org.eclipse.emf.common.util.URI) |
| */ |
| @Override |
| public IResourceDescription getResourceDescription(URI uri) { |
| return data.getResourceDescription(uri); |
| } |
| |
| } |
| |
| /** |
| * The Class LocalResourceAccess. |
| */ |
| public static class LocalResourceAccess implements IReferenceFinder.IResourceAccess { |
| |
| /** The rs. */ |
| private final ResourceSet rs; |
| |
| /** |
| * Instantiates a new local resource access. |
| * |
| * @param rs |
| * the rs |
| */ |
| public LocalResourceAccess(ResourceSet rs) { |
| this.rs = rs; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.xtext.findReferences.IReferenceFinder.IResourceAccess# |
| * readOnly(org.eclipse.emf.common.util.URI, |
| * org.eclipse.xtext.util.concurrent.IUnitOfWork) |
| */ |
| @Override |
| public <R> R readOnly(URI resourceURI, org.eclipse.xtext.util.concurrent.IUnitOfWork<R, ResourceSet> work) { |
| try { |
| return work.exec(rs); |
| } catch (Exception e) { |
| throw new IllegalStateException(e); |
| } |
| } |
| } |
| } |