/** * Copyright (c) 2015 committers of YAKINDU 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: * committers of YAKINDU - initial API and implementation * */ package org.yakindu.sct.domain.extension; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.Platform; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.URIConverter; import org.eclipse.xtext.EcoreUtil2; import org.osgi.framework.Bundle; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import org.yakindu.base.base.BasePackage; import org.yakindu.base.base.DomainElement; import org.yakindu.sct.domain.extension.DomainStatus.Severity; import org.yakindu.sct.domain.extension.impl.DomainImpl; import org.yakindu.sct.domain.extension.impl.ModuleContribution; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.inject.Module; /** * @author andreas muelder - Initial contribution and API * */ public class DomainRegistry { private static final String DOMAIN_EXTENSION_POINT_ID = "org.yakindu.sct.domain"; private static final String MODULES_EXTENSION_POINT_ID = "org.yakindu.sct.domain.modules"; public static final String DOMAIN_ID = "domainID"; private static final String DESCRIPTION = "description"; private static final String IMAGE = "image"; private static final String NAME = "name"; private static final String DOMAIN_STATUS_PROVIDER = "domainStatusProvider"; private static final String FEATURE = "feature"; private static final String MODULE_PROVIDER = "moduleProvider"; private DomainRegistry() { } private static List<IDomain> domainDescriptors; public static List<IDomain> getDomains() { if (domainDescriptors == null) { domainDescriptors = Lists.newArrayList(); if (Platform.isRunning()) { initFromExtensions(); } } return domainDescriptors; } public static IDomain getDomain(final String id) { final String defaultDomainID = BasePackage.Literals.DOMAIN_ELEMENT__DOMAIN_ID.getDefaultValueLiteral(); try { return Iterables.find(getDomains(), new Predicate<IDomain>() { @Override public boolean apply(IDomain input) { return input.getDomainID().equals(id != null ? id : defaultDomainID); } }); } catch (NoSuchElementException e) { if (defaultDomainID.equals(id)) { throw new IllegalArgumentException("No default domain found!"); } return getDomain(defaultDomainID); } } public static IDomain getDomain(EObject object) { DomainElement domainElement = EcoreUtil2.getContainerOfType(object, DomainElement.class); String domainID = domainElement != null ? domainElement.getDomainID() : BasePackage.Literals.DOMAIN_ELEMENT__DOMAIN_ID.getDefaultValueLiteral(); return getDomain(domainID); } public static boolean domainExists(final String domainID) { try { Iterables.find(getDomains(), new Predicate<IDomain>() { @Override public boolean apply(IDomain input) { return input.getDomainID().equals(domainID == null || domainID.isEmpty() ? BasePackage.Literals.DOMAIN_ELEMENT__DOMAIN_ID.getDefaultValueLiteral() : domainID); } }); } catch (NoSuchElementException e) { return false; } return true; } public static String determineDomainID(URI uri) { if (URIConverter.INSTANCE.exists(uri, null)) { return DomainIDParser.parse(uri); } return BasePackage.Literals.DOMAIN_ELEMENT__DOMAIN_ID.getDefaultValueLiteral(); } public static DomainStatus getDomainStatus(String domainID) { if (!DomainRegistry.domainExists(domainID)) { return new DomainStatus(Severity.ERROR, String.format(String.format("Domain '%s' is not available.", domainID))); } else { IDomain domain = DomainRegistry.getDomain(domainID); return domain.getAvailabilityStatus(); } } protected static void initFromExtensions() { List<ModuleContribution> moduleDescriptors = new ArrayList<>(); IConfigurationElement[] configurationElements = Platform.getExtensionRegistry() .getConfigurationElementsFor(MODULES_EXTENSION_POINT_ID); for (IConfigurationElement element : configurationElements) { moduleDescriptors.add(createModuleContribution(element)); } configurationElements = Platform.getExtensionRegistry().getConfigurationElementsFor(DOMAIN_EXTENSION_POINT_ID); for (IConfigurationElement iConfigurationElement : configurationElements) { domainDescriptors.add(createDomain(iConfigurationElement, moduleDescriptors)); } } protected static ModuleContribution createModuleContribution(IConfigurationElement element) { IModuleProvider provider; provider = new ModuleProviderProxy(element); return new ModuleContribution(element.getAttribute(DOMAIN_ID), element.getAttribute(FEATURE), provider); } protected static IDomain createDomain(final IConfigurationElement element, List<ModuleContribution> allModules) { String path = element.getAttribute(IMAGE); URL image = null; if (path != null) { Bundle extensionBundle = Platform.getBundle(element.getContributor().getName()); image = extensionBundle.getEntry(path); } IDomainStatusProvider provider = new IDomainStatusProvider.DefaultDomainStatusProvider(); if (element.getAttribute(DOMAIN_STATUS_PROVIDER) != null) { try { provider = (IDomainStatusProvider) element.createExecutableExtension(DOMAIN_STATUS_PROVIDER); } catch (CoreException e) { e.printStackTrace(); } } return new DomainImpl(element.getAttribute(DOMAIN_ID), element.getAttribute(NAME), element.getAttribute(DESCRIPTION), image, Iterables.filter(allModules, new Predicate<ModuleContribution>() { @Override public boolean apply(ModuleContribution input) { return input.getDomainID().equals(element.getAttribute(DOMAIN_ID)); } }), provider); } /** * Efficient parser to determine the DomainId without loading the whole resource * * @author Andreas Muelder - Initial contribution and API * */ protected static class DomainIDParser { private static final String SGRAPH_STATECHART = "sgraph:Statechart"; private static final String DOMAIN_ID = "domainID"; protected static class StopParsingException extends SAXException { private static final long serialVersionUID = 1L; } public static String parse(URI uri) { final StringBuilder result = new StringBuilder(); SAXParserFactory f = SAXParserFactory.newInstance(); try (InputStream is = URIConverter.INSTANCE.createInputStream(uri, null)) { SAXParser newSAXParser = f.newSAXParser(); newSAXParser.parse(is, new DefaultHandler() { @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (SGRAPH_STATECHART.equals(qName)) { String domainId = attributes.getValue(DOMAIN_ID); if (domainId != null) { result.append(domainId); } throw new StopParsingException(); } } }); } catch (StopParsingException e) { // Intentional to cancel parsing } catch (SAXException | IOException | ParserConfigurationException e) { e.printStackTrace(); } if (result.length() == 0) result.append(BasePackage.Literals.DOMAIN_ELEMENT__DOMAIN_ID.getDefaultValueLiteral()); return result.toString(); } } protected static class ModuleProviderProxy implements IModuleProvider { private IConfigurationElement element; private IModuleProvider provider; public ModuleProviderProxy(IConfigurationElement element) { this.element = element; } @Override public Module getModule(String... options) throws IllegalArgumentException { if (provider == null) { try { provider = (IModuleProvider) element.createExecutableExtension(MODULE_PROVIDER); } catch (CoreException e) { e.printStackTrace(); } } return provider.getModule(options); } } }