/* * Copyright 2009-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.groovy.frameworkadapter.util; import static org.codehaus.groovy.frameworkadapter.util.SpecifiedVersion.UNSPECIFIED; import java.lang.reflect.Method; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.FrameworkListener; import org.osgi.framework.Version; import org.osgi.service.packageadmin.PackageAdmin; import org.osgi.service.prefs.BackingStoreException; /** * This class chooses which Groovy compiler to use on startup * And it provides some other useful information about the compiler * @author Andrew Eisenberg * @created 2013-04-12 */ @SuppressWarnings("deprecation") public class CompilerChooser { private static CompilerChooser INSTANCE; private static final String GROOVY_COMPILER_LEVEL = "groovy.compiler.level"; private static final String DASH_GROOVY_COMPILER_LEVEL = "-groovy.compiler.level"; private static final String ECLIPSE_COMMANDS = "eclipse.commands"; private static final String GROOVY_PLUGIN_ID = "org.codehaus.groovy"; private Version[] allVersions = new Version[0]; private SpecifiedVersion[] allSpecifiedVersions = new SpecifiedVersion[0]; private int activeIndex = -1; private boolean initialized; CompilerChooser() { INSTANCE = this; } public static CompilerChooser getInstance() { return INSTANCE; } void initialize(final BundleContext context) throws BundleException { if (!initialized) { initialized = true; doInitialize(context); } } public boolean isInitiailzed() { return initialized; } private void doInitialize(BundleContext context) throws BundleException { SpecifiedVersion specifiedVersion = findSysPropVersion(); if (specifiedVersion == SpecifiedVersion.UNSPECIFIED) { // system property was unspecified, now try looking at configuration specifiedVersion = getVersionFromPrefenences(context); } System.out.println("Starting Groovy-Eclipse compiler resolver. Specified compiler level: " + specifiedVersion.toReadableVersionString()); Bundle[] bundles = Platform.getBundles(GROOVY_PLUGIN_ID, null); //Print debug infos about the bundles, to debug screwy behavior dump(bundles); if (bundles == null || bundles.length == 0) { System.out.println("No Groovy bundles found...this will cause some problems."); bundles = new Bundle[0]; } allVersions = new Version[bundles.length]; allSpecifiedVersions = new SpecifiedVersion[bundles.length]; if (specifiedVersion != SpecifiedVersion.UNSPECIFIED) { // if there are multiple bundles that match the SpecifiedVersion, let the latest one win out boolean found = false; for (int i = 0; i < bundles.length; i++) { Bundle bundle = bundles[i]; allVersions[i] = bundle.getVersion(); allSpecifiedVersions[i] = SpecifiedVersion.findVersion(bundle.getVersion()); if (allSpecifiedVersions[i] == specifiedVersion && !found) { activeIndex = i; found = true; } } // if activeIndex == 0, then there's nothing to do since specified bundle is already first // WRONG on e4.4 it looks like osgi remember which bundle was activated last time and will // use that one again, rather than automatically use latest available version. if (found /*&& activeIndex > 0*/) { for (int i = 0; i < bundles.length; i++) { Bundle bundle = bundles[i]; if (i != activeIndex) { System.out.println("Avoided bundle version = "+bundle.getVersion()); bundle.uninstall(); } else { System.out.println("Blessed bundle version = "+bundle.getVersion()); } } PackageAdmin pkgAdmin = context.getService(context.getServiceReference(org.osgi.service.packageadmin.PackageAdmin.class)); try { Method method = pkgAdmin.getClass().getMethod("refreshPackages", Bundle[].class, boolean.class, FrameworkListener[].class); if (method == null) { pkgAdmin.refreshPackages(bundles); } else { method.setAccessible(true); method.invoke(pkgAdmin, bundles, true, null); } } catch (Exception e) { pkgAdmin.refreshPackages(bundles); } } else { if (!found) { System.out.println("Specified version not found, using " + allVersions[0] + " instead."); } } } else { for (int i = 0; i < bundles.length; i++) { Bundle bundle = bundles[i]; allVersions[i] = bundle.getVersion(); allSpecifiedVersions[i] = SpecifiedVersion.findVersion(bundle.getVersion()); } } //Print debug infos about the bundles, to debug screwy behavior //dump(bundles); } private void dump(Bundle[] bundles) { for (int i = 0; i < bundles.length; i++) { Bundle b = bundles[i]; System.out.println(b.getBundleId() + " "+b.getVersion()+" = "+stateString(b.getState())); } } private static String stateString(int state) { switch (state) { case Bundle.ACTIVE: return "ACTIVE"; case Bundle.UNINSTALLED: return "UNINSTALLED"; case Bundle.INSTALLED: return "INSTALLED"; case Bundle.RESOLVED: return "RESOLVED"; case Bundle.STARTING: return "STARTING"; case Bundle.STOPPING: return "STOPPING"; default: return "UNKOWN("+state+")"; } } /** * Finds the compiler version that is specified in the system properties */ private SpecifiedVersion findSysPropVersion() { SpecifiedVersion version = SpecifiedVersion.findVersionFromString(System.getProperty(GROOVY_COMPILER_LEVEL)); if (version == UNSPECIFIED) { // now look at the non vmwargs version = internalFindCommandLineVersion(System.getProperty(ECLIPSE_COMMANDS)); } return version; } /** * @param property * @return */ private SpecifiedVersion internalFindCommandLineVersion( String property) { if (property == null) { return UNSPECIFIED; } String[] split = property.split("\\\n"); String versionText = null; for (int i = 0; i < split.length; i++) { if (DASH_GROOVY_COMPILER_LEVEL.equals(split[i]) && i < split.length-1) { versionText = split[i+1]; break; } } return SpecifiedVersion.findVersionFromString(versionText); } /** * Finds the compiler version that is specified in this plugin's configuration area, if it exists */ private SpecifiedVersion getVersionFromPrefenences(BundleContext context) { IEclipsePreferences prefNode = InstanceScope.INSTANCE.getNode(ResolverActivator.PLUGIN_ID); return SpecifiedVersion.findVersionFromString(prefNode.get(GROOVY_COMPILER_LEVEL, null)); } /** * Stores the {@link SpecifiedVersion} in Eclipse preferences * @param version the version to switch to * @throws BackingStoreException */ public void storeVersion(SpecifiedVersion version) throws BackingStoreException { IEclipsePreferences prefNode = InstanceScope.INSTANCE.getNode(ResolverActivator.PLUGIN_ID); prefNode.put(GROOVY_COMPILER_LEVEL, version.versionName); prefNode.flush(); } /** * @return the active groovy (specified) version */ public SpecifiedVersion getActiveSpecifiedVersion() { if (activeIndex == -1) { return SpecifiedVersion.findVersion(getActiveVersion()); } else { return allSpecifiedVersions[activeIndex]; } } public Version getActiveVersion() { if (activeIndex == -1) { Bundle bundle = getActiveBundle(); return bundle == null ? null : bundle.getVersion(); } else { return allVersions[activeIndex]; } } public Bundle getActiveBundle() { if (activeIndex == -1) { // Check if any of the org.codehaus.groovy bundles are active for (Bundle bundle : Platform.getBundles(GROOVY_PLUGIN_ID, null)) { if (bundle.getState() == Bundle.ACTIVE) { return bundle; } } // If none active just return the latest version bundle return Platform.getBundle(GROOVY_PLUGIN_ID); } else { Bundle[] bundles = Platform.getBundles(GROOVY_PLUGIN_ID, allVersions[activeIndex].toString()); if (bundles != null && bundles.length > 0) { // we are guaranteed that the highest installed bundle is the one being used. return bundles[0]; } } return null; } public SpecifiedVersion[] getAllSpecifiedVersions() { return allSpecifiedVersions; } public Version getAssociatedVersion(SpecifiedVersion specifiedVersion) { for (int i = 0; i < allSpecifiedVersions.length; i++) { if (allSpecifiedVersions[i] == specifiedVersion) { return allVersions[i]; } } return null; } }