/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common * Development and Distribution License("CDDL") (collectively, the * "License"). You may not use this file except in compliance with the * License. You can obtain a copy of the License at * http://www.netbeans.org/cddl-gplv2.html * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the * specific language governing permissions and limitations under the * License. When distributing the software, include this License Header * Notice in each file and include the License file at * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the * License Header, with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun * Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL * or only the GPL Version 2, indicate your decision by adding * "[Contributor] elects to include this software in this distribution * under the [CDDL or GPL Version 2] license." If you do not indicate a * single choice of license, a recipient has the option to distribute * your version of this file under either the CDDL, the GPL Version 2 or * to extend the choice of license to its licensees as provided above. * However, if you add GPL Version 2 code and therefore, elected the GPL * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. */ package org.netbeans; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.net.URL; import java.net.URLConnection; import java.security.AllPermission; import java.security.CodeSource; import java.security.PermissionCollection; import java.security.Permissions; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.StringTokenizer; import org.netbeans.core.workspaces.WorkspaceDescription; import org.netbeans.core.workspaces.WorkspaceServiceFactory; import org.netbeans.core.workspaces.WorkspaceShowOption; import org.openide.util.Lookup; import org.openide.util.lookup.Lookups; /** Bootstrap main class. * @author Jaroslav Tulach, Jesse Glick */ final class MainImpl extends Object { public static final String WORKSPACE_LAUNCHER_PARAM = "--workspace"; //TODO: What this method should do? public static void startWorkspaceLauncher() { } /** Starts the IDE. * @param args the command line arguments * @throws Exception for lots of reasons */ public static void main (String args[]) throws Exception { java.lang.reflect.Method[] m = new java.lang.reflect.Method[1]; int res = execute (args, System.in, System.out, System.err, m); if (res == -1) { // Connected to another running NB instance and succeeded in making a call. return; } else if (res != 0) { // Some CLIHandler refused the invocation System.exit(res); } m[0].invoke (null, new Object[] { args }); } /** Returns string describing usage of the system. Does that by talking to * all registered handlers and asking them to show their usage. * * @return the usage string for the system */ public static String usage () throws Exception { java.io.ByteArrayOutputStream os = new java.io.ByteArrayOutputStream (); java.io.ByteArrayOutputStream err = new java.io.ByteArrayOutputStream (); String[] newArgs = { "--help" }; execute(newArgs, System.in, os, err, null); return new String (os.toByteArray ()); } /** Constructs the correct ClassLoader, finds main method to execute * and invokes all registered CLIHandlers. * * @param args the arguments to pass to the handlers * @param reader the input stream reader for the handlers * @param writer the output stream for the handlers * @param methodToCall null or array with one item that will be set to * a method that shall be executed as the main application */ static int execute ( String[] args, java.io.InputStream reader, java.io.OutputStream writer, java.io.OutputStream error, java.lang.reflect.Method[] methodToCall ) throws Exception { // #42431: turn off jar: caches, they are evil // Note that setDefaultUseCaches changes a static field // yet for some reason it is an instance method! new URLConnection(MainImpl.class.getResource("Main.class")) { // NOI18N public void connect() throws IOException {} }.setDefaultUseCaches(false); ArrayList list = new ArrayList(); HashSet processedDirs = new HashSet (); HashSet processedPaths = new HashSet (); List argsL = Arrays.asList (args); // only nbexec.exe puts userdir into netbeans.user // #159555: This can be not true, but to avoid problems we assume that this property is equiv with --userdir String user = System.getProperty ("netbeans.user"); // NOI18N if (user == null) { // read userdir from args (for unix nbexec) int idx = argsL.indexOf ("--userdir"); // NOI18N if (idx != -1 && argsL.size () > idx + 1) { user = argsL.get (idx + 1); } } // #159555: Workspace support - check if don't start workspaces dialog WorkspaceDescription wd; boolean startWorkspaceLauncher = argsL.contains(WORKSPACE_LAUNCHER_PARAM); if (startWorkspaceLauncher) { wd = WorkspaceServiceFactory.newWorkspaceService().showWorkspaceFrame(WorkspaceShowOption.FORCE_DIALOG_SHOW); }else { wd = WorkspaceServiceFactory.newWorkspaceService().showWorkspaceFrame(); } if (wd != null) { if (wd instanceof WorkspaceDescription.DefaultWorkspaceDescription) { }else { user = wd.getDirectoryName(); // #159555: Workspace support - we need to modify args & argsL // to cheat next services (e. g. CLIHandler) :-( int idx = argsL.indexOf ("--userdir"); // NOI18N if (idx != -1 && argsL.size () > idx + 1) { argsL.set(++idx, user); args[idx] = user; } } }else { System.exit(0); } // #159555: End if (user != null) { build_cp (new File (user), list, processedDirs, processedPaths); } String home = System.getProperty ("netbeans.home"); // NOI18N if (home != null) { build_cp (new File (home), list, processedDirs, processedPaths); } // #34069: need to do the same for nbdirs. String nbdirs = System.getProperty("netbeans.dirs"); // NOI18N if (nbdirs != null) { StringTokenizer tok = new StringTokenizer(nbdirs, File.pathSeparator); while (tok.hasMoreTokens()) { // passing false as last argument as we need to initialize openfile-cli.jar build_cp(new File(tok.nextToken()), list, processedDirs, processedPaths); } } // // prepend classpath // String prepend = System.getProperty("netbeans.classpath"); // NOI18N if (prepend != null) { StringTokenizer tok = new StringTokenizer (prepend, File.pathSeparator); while (tok.hasMoreElements()) { File f = new File(tok.nextToken()); list.add(0, f); } } // Compute effective dynamic classpath (mostly lib/*.jar) for TopLogging, NbInstaller: StringBuffer buf = new StringBuffer(1000); for (File o : list) { String f = o.getAbsolutePath(); if (buf.length() > 0) { buf.append(File.pathSeparatorChar); } buf.append(f); } System.setProperty("netbeans.dynamic.classpath", buf.toString()); BootClassLoader loader = new BootClassLoader(list, new ClassLoader[] { MainImpl.class.getClassLoader() }); // Needed for Lookup.getDefault to find NbTopManager.Lkp. // Note that ModuleManager.updateContextClassLoaders will later change // the loader on this and other threads to be MM.SystemClassLoader anyway. Thread.currentThread().setContextClassLoader (loader); // // Evaluate command line interfaces and lock the user directory // CLIHandler.Status result; result = CLIHandler.initialize(args, reader, writer, error, loader, true, false, loader); if (result.getExitCode () == CLIHandler.Status.CANNOT_CONNECT) { int value = javax.swing.JOptionPane.showConfirmDialog ( null, java.util.ResourceBundle.getBundle("org/netbeans/Bundle").getString("MSG_AlreadyRunning"), java.util.ResourceBundle.getBundle("org/netbeans/Bundle").getString("MSG_AlreadyRunningTitle"), javax.swing.JOptionPane.OK_CANCEL_OPTION, javax.swing.JOptionPane.WARNING_MESSAGE ); if (value == javax.swing.JOptionPane.OK_OPTION) { result = CLIHandler.initialize(args, reader, writer, error, loader, true, true, loader); } } String className = System.getProperty( "netbeans.mainclass", "org.netbeans.core.startup.Main" // NOI18N ); Class c = loader.loadClass(className); Method m = c.getMethod ("main", String[].class); // NOI18N if (methodToCall != null) { methodToCall[0] = m; } return result.getExitCode (); } /** * Call when the system is up and running, to complete handling of * delayed command-line options like -open FILE. */ public static void finishInitialization() { int r = CLIHandler.finishInitialization (false); if (r != 0) { // Not much to do about it. System.err.println ("Post-initialization command-line options could not be run."); // NOI18N //System.err.println("r=" + r + " args=" + java.util.Arrays.asList(args.getArguments())); } } static final class BootClassLoader extends JarClassLoader implements Runnable { private Lookup metaInf; private List handlers; public BootClassLoader(List cp, ClassLoader[] parents) { super(cp, parents); metaInf = Lookups.metaInfServices(this); String value = null; try { if (cp.isEmpty ()) { value = searchBuildNumber(this.getResources("META-INF/MANIFEST.MF")); } else { value = searchBuildNumber(this.simpleFindResources("META-INF/MANIFEST.MF")); } } catch (IOException ex) { ex.printStackTrace(); } if (value == null) { System.err.println("Cannot set netbeans.buildnumber property no OpenIDE-Module-Build-Version found"); // NOI18N } else { System.setProperty ("netbeans.buildnumber", value); // NOI18N } } /** @param en enumeration of URLs */ private static String searchBuildNumber(Enumeration en) { String value = null; try { java.util.jar.Manifest mf; URL u = null; while(en.hasMoreElements()) { u = en.nextElement(); InputStream is = u.openStream(); mf = new java.util.jar.Manifest(is); is.close(); value = mf.getMainAttributes().getValue("OpenIDE-Module-Build-Version"); // NOI18N if (value != null) { break; } } } catch (IOException ex) { ex.printStackTrace(); } return value; } private boolean onlyRunRunOnce; /** Checks for new JARs in netbeans.user */ public void run () { // do not call this method twice if (onlyRunRunOnce) return; onlyRunRunOnce = true; ArrayList toAdd = new ArrayList (); String user = System.getProperty ("netbeans.user"); // NOI18N try { if (user != null) { JarClassLoader.initializeCache(); build_cp (new File (user), toAdd, new HashSet (), new HashSet ()); } if (!toAdd.isEmpty ()) { // source were already added in MainImpl.execute() method while processing userdir metaInf = Lookups.metaInfServices(this); if (handlers != null) { handlers.clear(); handlers.addAll(metaInf.lookupAll(CLIHandler.class)); } } } catch (IOException ex) { ex.printStackTrace(); } } /** #27226: startup optimization. */ @Override protected PermissionCollection getPermissions(CodeSource cs) { return getAllPermission(); } private static PermissionCollection modulePermissions; private static synchronized PermissionCollection getAllPermission() { if (modulePermissions == null) { modulePermissions = new Permissions(); modulePermissions.add(new AllPermission()); modulePermissions.setReadOnly(); } return modulePermissions; } /** For a given classloader finds all registered CLIHandlers. */ public final Collection allCLIs () { if (handlers == null) { handlers = new ArrayList(metaInf.lookupAll(CLIHandler.class)); } return handlers; } } // end of BootClassLoader private static void append_jars_to_cp (File base, String pathToDir, Collection toAdd, Set processedPaths) throws IOException { File dir = new File (base, pathToDir); if (!dir.isDirectory()) return; File[] arr = dir.listFiles(); for (int i = 0; i < arr.length; i++) { String n = arr[i].getName (); /* if (n.equals("updater.jar") || // NOI18N (dir.getName().equals("locale") && n.startsWith("updater_") && n.endsWith(".jar"))) { // NOI18N // Used by launcher, not by us. continue; } */ if (n.endsWith("jar") || n.endsWith ("zip")) { // NOI18N if (processedPaths.add (pathToDir + '/' + n)) { // NOI18N toAdd.add(arr[i]); } } } } private static void build_cp(File base, Collection toAdd, Set processedDirs, Set processedPaths) throws java.io.IOException { if (!processedDirs.add (base)) { // already processed return; } append_jars_to_cp(base, "core/patches", toAdd, processedPaths); // NOI18N append_jars_to_cp(base, "core", toAdd, processedPaths); // NOI18N // XXX a minor optimization: exclude any unused locale JARs // For example, lib/locale/ might contain: // core_ja.jar // core_f4j.jar // core_f4j_ja.jar // core_f4j_ce.jar // core_f4j_ce_ja.jar // core_ru.jar // core_fr.jar // [etc.] // Only some of these will apply to the current session, based on the // current values of Locale.default and NbBundle.branding. append_jars_to_cp(base, "core/locale", toAdd, processedPaths); // NOI18N } }