/** * Copyright (C) 2005 - 2014 Eric Van Dewoestine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.eclim.plugin.jdt; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FilenameFilter; import java.io.InputStream; import java.util.HashMap; import java.util.Properties; import java.util.regex.Pattern; import org.apache.commons.lang.SystemUtils; import org.apache.tools.ant.taskdefs.condition.Os; import org.eclim.Services; import org.eclim.logging.Logger; import org.eclim.plugin.AbstractPluginResources; import org.eclim.plugin.core.preference.PreferenceFactory; import org.eclim.plugin.core.preference.Preferences; import org.eclim.plugin.core.project.ProjectManagement; import org.eclim.plugin.core.project.ProjectNatureFactory; import org.eclim.plugin.jdt.preference.OptionHandler; import org.eclim.plugin.jdt.project.JavaProjectManager; import org.eclim.util.IOUtils; import org.eclim.util.StringUtils; import org.eclim.util.file.FileUtils; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jdt.launching.LibraryLocation; import org.eclipse.jdt.ui.JavaUI; /** * Implementation of AbstractPluginResources. * * @author Eric Van Dewoestine */ public class PluginResources extends AbstractPluginResources { /** * Name that can be used to lookup this PluginResources from * {@link Services#getPluginResources(String)}. */ public static final String NAME = "org.eclim.jdt"; /** * The eclipse nature id for this plugin. */ public static final String NATURE = JavaCore.NATURE_ID; private static final Logger logger = Logger.getLogger(PluginResources.class); private static final String VARIABLES = "resources/classpath_variables"; private static final String[] SRC_LOCATIONS = { "src.zip", "share/src.zip", SystemUtils.JAVA_HOME.replace('\\', '/') + "/src.jar", SystemUtils.JAVA_HOME.replace('\\', '/') + "/src.zip", SystemUtils.JAVA_HOME.replace('\\', '/') + "/share/src.zip", SystemUtils.JAVA_HOME.replace('\\', '/') + "/../src.zip", SystemUtils.JAVA_HOME.replace('\\', '/') + "/../share/src.zip", }; @Override public void initialize(String name) { super.initialize(name); logger.debug("Initializing java environment"); // initialize variables. initializeJreSrc(); initializeVars(VARIABLES); Preferences.addOptionHandler("org.eclipse.jdt", new OptionHandler()); ProjectNatureFactory.addNature("java", NATURE); ProjectManagement.addProjectManager(NATURE, new JavaProjectManager()); PreferenceFactory.addPreferences(NATURE, "JDT org.eclim.java.logging.impl commons-logging " + "(commons-logging|log4j|slf4j|jdk|custom)\n" + "JDT org.eclim.java.logging.template logger.gst\n" + "JDT org.eclim.java.import.package_separation_level 1 (-1|\\d+)\n" + "JDT org.eclim.java.import.exclude " + "[\"^com\\.sun\\..*\",\"^sunw\\?\\..*\"] JSON[]\n" + "JDT org.eclim.java.format.strip_trialing_whitespace true (true|false)\n" + "JDT org.eclim.java.checkstyle.config\n" + "JDT org.eclim.java.checkstyle.properties\n" + "JDT org.eclim.java.checkstyle.onvalidate false (true|false)\n" + "JDT org.eclim.java.run.mainclass none ^[a-zA-Z0-9_.]*$\n" + "JDT org.eclim.java.run.jvmargs [] JSON[^-.*]\n" + "JDT org.eclim.java.search.sort [] JSON[.*]\n" + "JDT/Javadoc org.eclim.java.doc.version\n" + "JDT/Javadoc org.eclim.java.doc.dest doc\n" + "JDT/Javadoc org.eclim.java.doc.sourcepath\n" + "JDT/Javadoc org.eclim.java.doc.packagenames\n" + "JDT/JUnit org.eclim.java.junit.output_dir\n" + "JDT/JUnit org.eclim.java.junit.cwd\n" + "JDT/JUnit org.eclim.java.junit.jvmargs [] JSON[^-.*]\n" + "JDT/JUnit org.eclim.java.junit.sysprops [] JSON[^(-D)?\\S+=.*]\n" + "JDT/JUnit org.eclim.java.junit.envvars [] JSON[^\\w+=.*]" ); // Indentation settings found in DefaultCodeFormatterConstants PreferenceFactory.addOptions(NATURE, "JDT org.eclipse.jdt.core.compiler.source 1\\.[3-8]\n" + "JDT org.eclipse.jdt.ui.importorder [a-zA-Z0-9_.#;]+\n" + "JDT/Javadoc " + JavaUI.ID_PLUGIN + ".project_javadoc_location\n" + "JDT/CodeComplete " + "org.eclipse.jdt.core.codeComplete.camelCaseMatch (enabled|disabled)\n" + "JDT/CodeComplete " + "org.eclipse.jdt.core.codeComplete.deprecationCheck (enabled|disabled)\n" + "JDT/CodeComplete " + "org.eclipse.jdt.core.codeComplete.visibilityCheck (enabled|disabled)" ); } @Override protected String getBundleBaseName() { return "org/eclim/plugin/jdt/messages"; } /** * Performs additional logic to locate jre src zip file in alternate locations * not checked by eclipse. */ protected void initializeJreSrc() { String jarName = Os.isFamily(Os.FAMILY_MAC) ? "classes.jar" : "rt.jar"; // doing a straight JavaCore.setClasspathVariable() doesn't work, so we need // to modify the library path of the default vm install. try{ IVMInstall vm = JavaRuntime.getDefaultVMInstall(); LibraryLocation[] locations = JavaRuntime.getLibraryLocations(vm); LibraryLocation[] newLocations = new LibraryLocation[locations.length]; for(int ii = 0; ii < locations.length; ii++){ IPath libraryPath = locations[ii].getSystemLibraryPath(); // eclipse didn't find src.zip, so search other known locations. if (libraryPath.lastSegment().equals(jarName) && (locations[ii].getSystemLibrarySourcePath().isEmpty() || !locations[ii].getSystemLibrarySourcePath().toFile().exists())) { IPath jreSrc = null; logger.debug("Attempting to locate jre src.zip for JAVA_HOME: {}", SystemUtils.JAVA_HOME); for (int jj = 0; jj < SRC_LOCATIONS.length; jj++){ String location = SRC_LOCATIONS[jj]; // absolute path if (location.startsWith("/") || location.indexOf(':') != -1) { jreSrc = new Path(location); // relative path }else{ jreSrc = libraryPath.removeLastSegments(3).append(location); } logger.debug("Trying location: {}", jreSrc); if(jreSrc.toFile().exists()){ break; } } // other possibilities on windows machines: // library path: C:/.../jre<version>/ // src archive: C:/.../jdk<version>/src.zip // or // library path: C:/.../jre<major>/ // src archive: C:/.../jdk1.<major>.<minor>_<patch>/src.zip if (!jreSrc.toFile().exists() && Os.isFamily(Os.FAMILY_WINDOWS)){ String path = libraryPath.toOSString() .replaceFirst("\\\\(lib\\\\)rt.jar", ""); // first scenerio String altHome = path.replaceFirst( "jre(\\d+\\.\\d+\\.\\d+_\\d+)", "jdk$1"); if (!altHome.equals(path)){ jreSrc = new Path(altHome).append("src.zip"); } // second scenerio if (!jreSrc.toFile().exists()){ String base = FileUtils.getBaseName(path); final String major = base.replaceFirst("^jre(\\d)$", "$1"); if (!major.equals(base)){ File dir = new File(FileUtils.getFullPath(path)); String[] jdks = dir.list(new FilenameFilter(){ private final Pattern JDK = Pattern.compile("jdk\\d+\\." + major + "\\.\\d+_\\d+"); public boolean accept(File dir, String name){ return JDK.matcher(name).matches(); } }); for (String jdk : jdks){ jreSrc = new Path(dir.toString()).append(jdk).append("src.zip"); if (jreSrc.toFile().exists()){ break; } } } } } // jre src found. if(jreSrc.toFile().exists()){ logger.info("Setting '{}' to '{}'", JavaRuntime.JRESRC_VARIABLE, jreSrc); newLocations[ii] = new LibraryLocation( locations[ii].getSystemLibraryPath(), jreSrc, locations[ii].getPackageRootPath(), locations[ii].getJavadocLocation()); // jre src not found. }else{ logger.debug( "Unable to locate jre src.zip for JAVA_HOME: " + SystemUtils.JAVA_HOME); newLocations[ii] = new LibraryLocation( locations[ii].getSystemLibraryPath(), Path.EMPTY, locations[ii].getPackageRootPath(), locations[ii].getJavadocLocation()); } }else{ newLocations[ii] = locations[ii]; } } vm.setLibraryLocations(newLocations); }catch(Exception e){ logger.error("", e); } } /** * Loads variables from property file. * * @param variable The prefix of the property file. */ protected void initializeVars(String variable) { String file = "/" + variable + ".properties"; logger.debug("Loading classpath variables from '{}'.", file); InputStream in = null; try{ in = getClass().getResourceAsStream(file); String propertiesString = IOUtils.toString(in); HashMap<Object, String> values = new HashMap<Object, String>(); for(Object key : System.getProperties().keySet()){ String value = System.getProperty((String)key); if (value != null){ values.put(key, value.replace('\\', '/')); } } propertiesString = StringUtils.replacePlaceholders(propertiesString, values); Properties properties = new Properties(); properties.load(new ByteArrayInputStream(propertiesString.getBytes())); for(Object key : properties.keySet()){ String name = (String)key; IPath path = new Path(properties.getProperty(name)); logger.debug("Setting classpath variable '{}' to path '{}'", name, path); JavaCore.setClasspathVariable(name, path, null); } }catch(Exception e){ logger.error("", e); }finally{ IOUtils.closeQuietly(in); } } }