| /* |
| * Copyright 2000-2014 JetBrains s.r.o. |
| * |
| * 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 com.intellij.idea; |
| |
| import com.intellij.openapi.application.ApplicationInfo; |
| import com.intellij.openapi.application.ApplicationNamesInfo; |
| import com.intellij.openapi.application.ConfigImportHelper; |
| import com.intellij.openapi.application.PathManager; |
| import com.intellij.openapi.application.impl.ApplicationInfoImpl; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.util.SystemInfo; |
| import com.intellij.openapi.util.SystemInfoRt; |
| import com.intellij.openapi.util.io.FileUtil; |
| import com.intellij.openapi.util.io.FileUtilRt; |
| import com.intellij.openapi.util.io.win32.IdeaWin32; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.ui.AppUIUtil; |
| import com.intellij.util.Consumer; |
| import com.intellij.util.EnvironmentUtil; |
| import com.intellij.util.lang.UrlClassLoader; |
| import com.sun.jna.Native; |
| import org.jetbrains.annotations.NonNls; |
| |
| import javax.swing.*; |
| import java.io.File; |
| import java.lang.management.ManagementFactory; |
| import java.text.SimpleDateFormat; |
| import java.util.*; |
| |
| /** |
| * @author yole |
| */ |
| public class StartupUtil { |
| @NonNls public static final String NO_SPLASH = "nosplash"; |
| |
| private static SocketLock ourLock; |
| private static String myDefaultLAF; |
| private static String myWizardLAF; |
| private static String myWizardMacKeymap; |
| private static Set<String> myFeaturedPluginsToInstall = new HashSet<String>(); |
| |
| private StartupUtil() { } |
| |
| public static void setDefaultLAF(String laf) { |
| myDefaultLAF = laf; |
| } |
| |
| public static String getDefaultLAF() { |
| return myDefaultLAF; |
| } |
| |
| public static void setWizardLAF(String myWizardLAF) { |
| StartupUtil.myWizardLAF = myWizardLAF; |
| } |
| |
| public static String getWizardLAF() { |
| return myWizardLAF; |
| } |
| |
| public static void setMyWizardMacKeymap(String myWizardMacKeymap) { |
| StartupUtil.myWizardMacKeymap = myWizardMacKeymap; |
| } |
| |
| public static String getMyWizardMacKeymap() { |
| return myWizardMacKeymap; |
| } |
| |
| public static Set<String> getMyFeaturedPluginsToInstall() { |
| return Collections.unmodifiableSet(myFeaturedPluginsToInstall); |
| } |
| |
| public static void setFeaturedPluginsToInstall(Set<String> pluginsToInstall) { |
| myFeaturedPluginsToInstall.clear(); |
| myFeaturedPluginsToInstall.addAll(pluginsToInstall); |
| } |
| |
| public static boolean shouldShowSplash(final String[] args) { |
| return !Arrays.asList(args).contains(NO_SPLASH); |
| } |
| |
| /** @deprecated use {@link Main#isHeadless()} (to remove in IDEA 14) */ |
| @SuppressWarnings("unused") |
| public static boolean isHeadless() { |
| return Main.isHeadless(); |
| } |
| |
| public synchronized static void addExternalInstanceListener(Consumer<List<String>> consumer) { |
| ourLock.setActivateListener(consumer); |
| } |
| |
| interface AppStarter { |
| void start(boolean newConfigFolder); |
| } |
| |
| public synchronized static int getAcquiredPort() { |
| return ourLock.getAcquiredPort(); |
| } |
| |
| static void prepareAndStart(String[] args, AppStarter appStarter) { |
| boolean newConfigFolder = false; |
| |
| if (!Main.isHeadless()) { |
| AppUIUtil.updateFrameClass(); |
| newConfigFolder = !new File(PathManager.getConfigPath()).exists(); |
| } |
| |
| boolean canStart = checkJdkVersion() && checkSystemFolders() && lockSystemFolders(args); // note: uses config folder! |
| if (!canStart) { |
| System.exit(Main.STARTUP_IMPOSSIBLE); |
| } |
| |
| if (newConfigFolder) { |
| ConfigImportHelper.importConfigsTo(PathManager.getConfigPath()); |
| } |
| |
| Logger.setFactory(LoggerFactory.class); |
| Logger log = Logger.getInstance(Main.class); |
| startLogging(log); |
| loadSystemLibraries(log); |
| Main.dumpDelayedLogging(log); |
| fixProcessEnvironment(log); |
| |
| if (!Main.isHeadless()) { |
| AppUIUtil.updateWindowIcon(JOptionPane.getRootFrame()); |
| AppUIUtil.registerBundledFonts(); |
| } |
| |
| appStarter.start(newConfigFolder); |
| } |
| |
| /** |
| * Checks if the program can run under the JDK it was started with. |
| */ |
| private static boolean checkJdkVersion() { |
| if (!"true".equals(System.getProperty("idea.no.jre.check"))) { |
| try { |
| // try to find a class from tools.jar |
| Class.forName("com.sun.jdi.Field"); |
| } |
| catch (ClassNotFoundException e) { |
| String message = "'tools.jar' seems to be not in " + ApplicationNamesInfo.getInstance().getProductName() + " classpath.\n" + |
| "Please ensure JAVA_HOME points to JDK rather than JRE."; |
| Main.showMessage("JDK Required", message, true); |
| return false; |
| } |
| |
| if (StringUtil.containsIgnoreCase(System.getProperty("java.vm.name", ""), "OpenJDK") && !SystemInfo.isJavaVersionAtLeast("1.7")) { |
| String message = "OpenJDK 6 is not supported. Please use Oracle Java or newer OpenJDK."; |
| Main.showMessage("Unsupported JVM", message, true); |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| private synchronized static boolean checkSystemFolders() { |
| String configPath = PathManager.getConfigPath(); |
| PathManager.ensureConfigFolderExists(); |
| if (!new File(configPath).isDirectory()) { |
| String message = "Config path '" + configPath + "' is invalid.\n" + |
| "If you have modified the '" + PathManager.PROPERTY_CONFIG_PATH + "' property please make sure it is correct,\n" + |
| "otherwise please re-install the IDE."; |
| Main.showMessage("Invalid Config Path", message, true); |
| return false; |
| } |
| |
| String systemPath = PathManager.getSystemPath(); |
| if (!new File(systemPath).isDirectory()) { |
| String message = "System path '" + systemPath + "' is invalid.\n" + |
| "If you have modified the '" + PathManager.PROPERTY_SYSTEM_PATH + "' property please make sure it is correct,\n" + |
| "otherwise please re-install the IDE."; |
| Main.showMessage("Invalid System Path", message, true); |
| return false; |
| } |
| |
| File ideTempDir = new File(PathManager.getTempPath()); |
| String tempInaccessible = null; |
| |
| if (!ideTempDir.isDirectory() && !ideTempDir.mkdirs()) { |
| tempInaccessible = "unable to create the directory"; |
| } |
| else { |
| try { |
| File ideTempFile = new File(ideTempDir, "idea_tmp_check.sh"); |
| FileUtil.writeToFile(ideTempFile, "#!/bin/sh\nexit 0"); |
| |
| if (SystemInfo.isWindows || SystemInfo.isMac) { |
| tempInaccessible = null; |
| } |
| else if (!ideTempFile.setExecutable(true, true)) { |
| tempInaccessible = "cannot set executable permission"; |
| } |
| else if (new ProcessBuilder(ideTempFile.getAbsolutePath()).start().waitFor() != 0) { |
| tempInaccessible = "cannot execute test script"; |
| } |
| |
| if (!FileUtilRt.delete(ideTempFile)) { |
| ideTempFile.deleteOnExit(); |
| } |
| } |
| catch (Exception e) { |
| tempInaccessible = e.getClass().getSimpleName() + ": " + e.getMessage(); |
| } |
| } |
| |
| if (tempInaccessible != null) { |
| String message = "Temp directory '" + ideTempDir + "' is inaccessible.\n" + |
| "If you have modified the '" + PathManager.PROPERTY_SYSTEM_PATH + "' property please make sure it is correct,\n" + |
| "otherwise please re-install the IDE.\n\nDetails: " + tempInaccessible; |
| Main.showMessage("Invalid System Path", message, true); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| private synchronized static boolean lockSystemFolders(String[] args) { |
| if (ourLock == null) { |
| ourLock = new SocketLock(); |
| } |
| |
| SocketLock.ActivateStatus activateStatus = ourLock.lock(PathManager.getConfigPath(), true, args); |
| if (activateStatus == SocketLock.ActivateStatus.NO_INSTANCE) { |
| activateStatus = ourLock.lock(PathManager.getSystemPath(), false); |
| } |
| |
| if (activateStatus != SocketLock.ActivateStatus.NO_INSTANCE) { |
| if (Main.isHeadless() || activateStatus == SocketLock.ActivateStatus.CANNOT_ACTIVATE) { |
| String message = "Only one instance of " + ApplicationNamesInfo.getInstance().getFullProductName() + " can be run at a time."; |
| Main.showMessage("Too Many Instances", message, true); |
| } |
| return false; |
| } |
| |
| return true; |
| } |
| |
| private static void fixProcessEnvironment(Logger log) { |
| if (!Main.isCommandLine()) { |
| System.setProperty("__idea.mac.env.lock", "unlocked"); |
| } |
| boolean envReady = EnvironmentUtil.isEnvironmentReady(); // trigger environment loading |
| if (!envReady) { |
| log.info("initializing environment"); |
| } |
| } |
| |
| private static final String JAVA_IO_TEMP_DIR = "java.io.tmpdir"; |
| |
| private static void loadSystemLibraries(final Logger log) { |
| // load JNA and Snappy in own temp directory - to avoid collisions and work around no-exec /tmp |
| File ideTempDir = new File(PathManager.getTempPath()); |
| if (!(ideTempDir.mkdirs() || ideTempDir.exists())) { |
| throw new RuntimeException("Unable to create temp directory '" + ideTempDir + "'"); |
| } |
| |
| String javaTempDir = System.getProperty(JAVA_IO_TEMP_DIR); |
| try { |
| System.setProperty(JAVA_IO_TEMP_DIR, ideTempDir.getPath()); |
| if (System.getProperty("jna.nosys") == null && System.getProperty("jna.nounpack") == null) { |
| // force using bundled JNA dispatcher (if not explicitly stated) |
| System.setProperty("jna.nosys", "true"); |
| System.setProperty("jna.nounpack", "false"); |
| } |
| try { |
| final long t = System.currentTimeMillis(); |
| log.info("JNA library loaded (" + (Native.POINTER_SIZE * 8) + "-bit) in " + (System.currentTimeMillis() - t) + " ms"); |
| } |
| catch (Throwable t) { |
| logError(log, "Unable to load JNA library", t); |
| } |
| } |
| finally { |
| System.setProperty(JAVA_IO_TEMP_DIR, javaTempDir); |
| } |
| |
| if (SystemInfo.isWin2kOrNewer) { |
| IdeaWin32.isAvailable(); // logging is done there |
| } |
| |
| if (SystemInfo.isWin2kOrNewer && !Main.isHeadless()) { |
| try { |
| UrlClassLoader.loadPlatformLibrary("focusKiller"); |
| log.info("Using \"FocusKiller\" library to prevent focus stealing."); |
| } |
| catch (Throwable t) { |
| log.info("\"FocusKiller\" library not found or there were problems loading it.", t); |
| } |
| } |
| } |
| |
| private static void logError(Logger log, String message, Throwable t) { |
| message = message + " (OS: " + SystemInfo.OS_NAME + " " + SystemInfo.OS_VERSION + ")"; |
| log.error(message, t); |
| } |
| |
| private static void startLogging(final Logger log) { |
| Runtime.getRuntime().addShutdownHook(new Thread("Shutdown hook - logging") { |
| @Override |
| public void run() { |
| log.info("------------------------------------------------------ IDE SHUTDOWN ------------------------------------------------------"); |
| } |
| }); |
| log.info("------------------------------------------------------ IDE STARTED ------------------------------------------------------"); |
| |
| ApplicationInfo appInfo = ApplicationInfoImpl.getShadowInstance(); |
| ApplicationNamesInfo namesInfo = ApplicationNamesInfo.getInstance(); |
| String buildDate = new SimpleDateFormat("dd MMM yyyy HH:ss", Locale.US).format(appInfo.getBuildDate().getTime()); |
| log.info("IDE: " + namesInfo.getFullProductName() + " (build #" + appInfo.getBuild().asStringWithAllDetails() + ", " + buildDate + ")"); |
| log.info("OS: " + SystemInfoRt.OS_NAME + " (" + SystemInfoRt.OS_VERSION + ", " + SystemInfo.OS_ARCH + ")"); |
| log.info("JRE: " + System.getProperty("java.runtime.version", "-") + " (" + System.getProperty("java.vendor", "-") + ")"); |
| log.info("JVM: " + System.getProperty("java.vm.version", "-") + " (" + System.getProperty("java.vm.name", "-") + ")"); |
| |
| List<String> arguments = ManagementFactory.getRuntimeMXBean().getInputArguments(); |
| if (arguments != null) { |
| log.info("JVM Args: " + StringUtil.join(arguments, " ")); |
| } |
| } |
| } |