/**
   * Splits a classpath into elements using the <code>path.separator</code> system property.
   *
   * @param elements the <code>Vector</code> to which to add the classpath elements
   * @param classpath the classpath to split
   */
  private static void splitClassPath(final Vector elements, final String classpath) {
    String separator = System.getProperty("path.separator");
    if (separator == null) {
      // defaults to ';'
      separator = ";";

      Logging.report(
          Logging.ERROR,
          LogChannels.LC_AMS,
          "No \"path.separator\" defined! Using \"" + separator + "\"!");
    }

    int index = classpath.indexOf(separator);
    int offset = 0;
    while (index != -1) {
      addClassPathElement(elements, classpath, offset, index);

      offset = index + separator.length();
      index = classpath.indexOf(separator, offset);
    }

    addClassPathElement(elements, classpath, offset, classpath.length());
  }
  /**
   * Starts a MIDlet in a new Isolate. Check that the MIDlet is is not realy running and is not
   * already being started. If so, return immediately.
   *
   * @param midletSuiteStorage midletSuiteStorage for obtaining a classpath
   * @param externalAppId ID of MIDlet to invoke, given by an external application manager
   * @param id ID of an installed suite
   * @param midlet class name of MIDlet to invoke
   * @param displayName name to display to the user
   * @param arg0 if not null, this parameter will be available to the MIDlet as application property
   *     arg-0
   * @param arg1 if not null, this parameter will be available to the MIDlet as application property
   *     arg-1
   * @param arg2 if not null, this parameter will be available to the MIDlet as application property
   *     arg-2
   * @param memoryReserved the minimum amount of memory guaranteed to be available to the isolate at
   *     any time; &lt; 0 if not used
   * @param memoryTotal the total amount of memory that the isolate can reserve; &lt; 0 if not used
   * @param priority priority to set for the new isolate; &lt;= 0 if not used
   * @param profileName name of the profile to set for the new isolate; null if not used
   * @param debugMode debug option for the new isolate, one of: MIDP_NO_DEBUG, MIDP_DEBUG_SUSPEND,
   *     MIDP_DEBUG_NO_SUSPEND
   * @return Isolate that the MIDlet suite was started in; <code>null</code> if the MIDlet is
   *     already running
   */
  private static Isolate startMidletCommon(
      MIDletSuiteStorage midletSuiteStorage,
      int externalAppId,
      int id,
      String midlet,
      String displayName,
      String arg0,
      String arg1,
      String arg2,
      int memoryReserved,
      int memoryTotal,
      int priority,
      String profileName,
      int debugMode) {
    Isolate isolate;
    String[] args = {
      Integer.toString(id),
      midlet,
      displayName,
      arg0,
      arg1,
      arg2,
      Integer.toString(externalAppId),
      String.valueOf(debugMode)
    };
    String[] classpath = midletSuiteStorage.getMidletSuiteClassPath(id);

    if (classpath[0] == null) {
      if (id == MIDletSuite.INTERNAL_SUITE_ID) {
        /*
         * Avoid a null pointer exception, rommized midlets don't need
         * a classpath.
         */
        classpath[0] = "";
      } else {
        throw new IllegalArgumentException("Suite " + id + " not found");
      }
    }

    Vector cpExtElements = new Vector();

    String isolateClassPath = System.getProperty("classpathext");
    if (isolateClassPath != null) {
      splitClassPath(cpExtElements, isolateClassPath);
    }

    /*
     * Include paths to dynamic components belonging to this suite
     * and to the "internal" suite (actually, to AMS) into class
     * path for the new Isolate.
     */
    DynamicComponentStorage componentStorage = DynamicComponentStorage.getComponentStorage();
    ComponentInfo[] ci = componentStorage.getListOfSuiteComponents(id);
    ComponentInfo[] ciAms =
        componentStorage.getListOfSuiteComponents(MIDletSuite.INTERNAL_SUITE_ID);
    int numOfComponents = 0;

    // calculate the number of the components to be added to the class path
    if (ci != null) {
      numOfComponents += ci.length;
    }

    if (ciAms != null) {
      numOfComponents += ciAms.length;
    }

    if (numOfComponents > 0) {
      Vector ciVector = new Vector(numOfComponents);

      // add the suite's own components
      if (ci != null) {
        for (int i = 0; i < ci.length; i++) {
          ciVector.addElement(ci[i]);
        }
      }

      // add the shared (belonging to AMS) components
      if (ciAms != null) {
        for (int i = 0; i < ciAms.length; i++) {
          ciVector.addElement(ciAms[i]);
        }
      }

      /*
       * IMPL_NOTE: currently is assumed that each component may have
       *            not more than 1 entry in class path.
       *            Later it will be possible to have 2: 1 for MONET.
       *            + 1 is for System.getProperty("classpathext").
       */
      int n = 0;

      try {
        for (int i = 0; i < ciVector.size(); i++) {
          final ComponentInfo nextComponent = ((ComponentInfo) ciVector.elementAt(i));
          final String[] componentPath =
              componentStorage.getComponentClassPath(nextComponent.getComponentId());
          if (componentPath != null) {
            for (int j = 0; j < componentPath.length; j++) {
              cpExtElements.addElement(componentPath[j]);
              ++n;
            }
          }
        }
      } catch (Exception e) {
        /*
         * if something is wrong with a dynamic component, just
         * don't use the components, this error is not fatal
         */
        cpExtElements.setSize(cpExtElements.size() - n);

        if (Logging.REPORT_LEVEL <= Logging.ERROR) {
          e.printStackTrace();
          Logging.report(
              Logging.ERROR,
              LogChannels.LC_AMS,
              "Cannot use a dynamic component when starting '"
                  + midlet
                  + "' from the suite with id = "
                  + id);
        }
      }
    }

    try {
      StartMIDletMonitor app = StartMIDletMonitor.okToStart(id, midlet);
      if (app == null) {
        // Isolate is already running; don't start it again
        return null;
      }

      final String[] classpathext = new String[cpExtElements.size()];
      cpExtElements.copyInto(classpathext);

      isolate =
          new Isolate(
              "com.sun.midp.main.AppIsolateMIDletSuiteLoader", args, classpath, classpathext);
      app.setIsolate(isolate);
    } catch (Throwable t) {
      t.printStackTrace();
      throw new RuntimeException("Can't create Isolate****");
    }

    try {
      int reserved, limit;

      if (memoryReserved >= 0) {
        reserved = memoryReserved;
      } else {
        reserved = Constants.SUITE_MEMORY_RESERVED * 1024;
      }

      if (memoryTotal > 0) {
        limit = memoryTotal;
      } else {
        limit = Constants.SUITE_MEMORY_LIMIT;
        if (limit < 0) {
          limit = isolate.totalMemory();
        } else {
          limit = limit * 1024;
        }

        int heapSize = getMidletHeapSize(id, midlet);
        if ((heapSize > 0) && (heapSize < limit)) {
          limit = heapSize;
        }
      }

      isolate.setMemoryQuota(reserved, limit);

      if (priority >= Isolate.MIN_PRIORITY) {
        isolate.setPriority(priority);
      }

      if (profileName != null) {
        IsolateUtil.setProfile(isolate, profileName);
      }

      isolate.setDebug(debugMode);

      isolate.setAPIAccess(true);
      isolate.start();

      // Ability to launch midlet implies right to use Service API
      // for negotiations with isolate being run
      Link[] isolateLinks = SystemServiceLinkPortal.establishLinksFor(isolate, getTrustedToken());
      LinkPortal.setLinks(isolate, isolateLinks);
    } catch (Throwable t) {
      int errorCode;
      String msg;

      if (Logging.REPORT_LEVEL <= Logging.WARNING) {
        t.printStackTrace();
      }

      if (t instanceof IsolateStartupException) {
        /*
         * An error occured in the
         * initialization or configuration of the new isolate
         * before any application code is invoked, or if this
         * Isolate was already started or is terminated.
         */
        errorCode = Constants.MIDLET_ISOLATE_CONSTRUCTOR_FAILED;
        msg = "Can't start Application.";
      } else if (t instanceof IsolateResourceError) {
        /* The system has exceeded the maximum Isolate count. */
        errorCode = Constants.MIDLET_ISOLATE_RESOURCE_LIMIT;
        msg = "No more concurrent applications allowed.";
      } else if (t instanceof IllegalArgumentException) {
        /* Requested profile doesn't exist. */
        errorCode = Constants.MIDLET_ISOLATE_CONSTRUCTOR_FAILED;
        msg = "Invalid profile name: " + profileName;
      } else if (t instanceof OutOfMemoryError) {
        /* The reserved memory cannot be allocated */
        errorCode = Constants.MIDLET_OUT_OF_MEM_ERROR;
        msg = "Not enough memory to run the application.";
      } else {
        errorCode = Constants.MIDLET_ISOLATE_CONSTRUCTOR_FAILED;
        msg = t.toString();
      }

      midletControllerEventProducer.sendMIDletStartErrorEvent(
          id, midlet, externalAppId, errorCode, msg);

      throw new RuntimeException(msg);
    }

    return isolate;
  }