Beispiel #1
0
  @Override
  public void engineLoad(KeyStore.LoadStoreParameter param)
      throws IOException, NoSuchAlgorithmException, CertificateException {
    if (param instanceof DomainLoadStoreParameter) {
      DomainLoadStoreParameter domainParameter = (DomainLoadStoreParameter) param;
      List<KeyStoreBuilderComponents> builders =
          getBuilders(domainParameter.getConfiguration(), domainParameter.getProtectionParams());

      for (KeyStoreBuilderComponents builder : builders) {

        try {
          // Load the keystores (file-based and non-file-based)
          if (builder.file != null) {
            keystores.put(
                builder.name,
                KeyStore.Builder.newInstance(
                        builder.type, builder.provider, builder.file, builder.protection)
                    .getKeyStore());
          } else {
            keystores.put(
                builder.name,
                KeyStore.Builder.newInstance(builder.type, builder.provider, builder.protection)
                    .getKeyStore());
          }
        } catch (KeyStoreException e) {
          throw new IOException(e);
        }
      }
    } else {
      throw new UnsupportedOperationException(
          "This keystore must be loaded using a " + "DomainLoadStoreParameter");
    }
  }
  MemoryUsage getPeakMemoryUsage() {
    try {
      final Map<Object, Object> m = JvmContextFactory.getUserData();

      if (m != null) {
        final MemoryUsage cached = (MemoryUsage) m.get(entryPeakMemoryTag);
        if (cached != null) {
          if (log.isDebugOn())
            log.debug("getPeakMemoryUsage", entryPeakMemoryTag + " found in cache.");
          return cached;
        }

        MemoryUsage u = pool.getPeakUsage();
        if (u == null) u = ZEROS;

        m.put(entryPeakMemoryTag, u);
        return u;
      }
      // Should never come here.
      // Log error!
      log.trace("getPeakMemoryUsage", "ERROR: should never come here!");
      return ZEROS;
    } catch (RuntimeException x) {
      log.trace("getPeakMemoryUsage", "Failed to get MemoryUsage: " + x);
      log.debug("getPeakMemoryUsage", x);
      throw x;
    }
  }
Beispiel #3
0
 /** Get an image ref. */
 static Ref getCachedImageRef(URL url) {
   synchronized (imageRefs) {
     AppletImageRef ref = (AppletImageRef) imageRefs.get(url);
     if (ref == null) {
       ref = new AppletImageRef(url);
       imageRefs.put(url, ref);
     }
     return ref;
   }
 }
Beispiel #4
0
 /** Get an audio clip. */
 public AudioClip getAudioClip(URL url) {
   checkConnect(url);
   synchronized (audioClips) {
     AudioClip clip = (AudioClip) audioClips.get(url);
     if (clip == null) {
       audioClips.put(url, clip = new AppletAudioClip(url));
     }
     return clip;
   }
 }
Beispiel #5
0
 final EventDispatcher getEventDispatcher() {
   // create and start the global event thread
   // TODO  need a way to stop this thread when the engine is done
   final ThreadGroup tg = Thread.currentThread().getThreadGroup();
   synchronized (dispatchers) {
     EventDispatcher eventDispatcher = dispatchers.get(tg);
     if (eventDispatcher == null) {
       eventDispatcher = new EventDispatcher();
       dispatchers.put(tg, eventDispatcher);
       eventDispatcher.start();
     }
     return eventDispatcher;
   }
 }
Beispiel #6
0
  private void addDefault(String key, Object value) {
    if (compiledDefaults == null) {
      return;
    }

    String prefix = parsePrefix(key);
    if (prefix != null) {
      Map<String, Object> keys = compiledDefaults.get(prefix);
      if (keys == null) {
        keys = new HashMap<String, Object>();
        compiledDefaults.put(prefix, keys);
      }
      keys.put(key, value);
    }
  }
Beispiel #7
0
  /**
   * Stores this keystore to the given output stream, and protects its integrity with the given
   * password.
   *
   * @param stream the output stream to which this keystore is written.
   * @param password the password to generate the keystore integrity check
   * @exception IOException if there was an I/O problem with data
   * @exception NoSuchAlgorithmException if the appropriate data integrity algorithm could not be
   *     found
   * @exception CertificateException if any of the certificates included in the keystore data could
   *     not be stored
   */
  public void engineStore(OutputStream stream, char[] password)
      throws IOException, NoSuchAlgorithmException, CertificateException {
    // Support storing to a stream only when a single keystore has been
    // configured
    try {
      if (keystores.size() == 1) {
        keystores.values().iterator().next().store(stream, password);
        return;
      }
    } catch (KeyStoreException e) {
      throw new IllegalStateException(e);
    }

    throw new UnsupportedOperationException(
        "This keystore must be stored using a DomainLoadStoreParameter");
  }
Beispiel #8
0
 String connectorArg(String name) {
   Connector.Argument argument = connectorArgs.get(name);
   if (argument == null) {
     return "";
   }
   return argument.value();
 }
Beispiel #9
0
  /**
   * Loads the keystore from the given input stream.
   *
   * <p>If a password is given, it is used to check the integrity of the keystore data. Otherwise,
   * the integrity of the keystore is not checked.
   *
   * @param stream the input stream from which the keystore is loaded
   * @param password the (optional) password used to check the integrity of the keystore.
   * @exception IOException if there is an I/O or format problem with the keystore data
   * @exception NoSuchAlgorithmException if the algorithm used to check the integrity of the
   *     keystore cannot be found
   * @exception CertificateException if any of the certificates in the keystore could not be loaded
   */
  public void engineLoad(InputStream stream, char[] password)
      throws IOException, NoSuchAlgorithmException, CertificateException {
    // Support loading from a stream only for a JKS or default type keystore
    try {
      KeyStore keystore = null;

      try {
        keystore = KeyStore.getInstance("JKS");
        keystore.load(stream, password);

      } catch (Exception e) {
        // Retry
        if (!"JKS".equalsIgnoreCase(DEFAULT_KEYSTORE_TYPE)) {
          keystore = KeyStore.getInstance(DEFAULT_KEYSTORE_TYPE);
          keystore.load(stream, password);
        } else {
          throw e;
        }
      }
      String keystoreName = DEFAULT_STREAM_PREFIX + streamCounter++;
      keystores.put(keystoreName, keystore);

    } catch (Exception e) {
      throw new UnsupportedOperationException(
          "This keystore must be loaded using a " + "DomainLoadStoreParameter");
    }
  }
Beispiel #10
0
  /*
   * Returns a keystore entry alias and a list of target keystores.
   * When the supplied alias prefix identifies a keystore then that single
   * keystore is returned. When no alias prefix is supplied then all the
   * keystores are returned.
   */
  private AbstractMap.SimpleEntry<String, Collection<KeyStore>> getKeystoresForReading(
      String alias) {

    String[] splits = alias.split(this.entryNameSeparatorRegEx, 2);
    if (splits.length == 2) { // prefixed alias
      KeyStore keystore = keystores.get(splits[0]);
      if (keystore != null) {
        return new AbstractMap.SimpleEntry<>(
            splits[1], (Collection<KeyStore>) Collections.singleton(keystore));
      }
    } else if (splits.length == 1) { // unprefixed alias
      // Check all keystores for the first occurrence of the alias
      return new AbstractMap.SimpleEntry<>(alias, keystores.values());
    }
    return new AbstractMap.SimpleEntry<>(
        "", (Collection<KeyStore>) Collections.<KeyStore>emptyList());
  }
  private static SortedMap<String, Object> makeMap(Map<String, ?> items) {
    if (items == null || items.isEmpty())
      throw new IllegalArgumentException("Null or empty items map");

    SortedMap<String, Object> map = new TreeMap<String, Object>();
    for (Object key : items.keySet()) {
      if (key == null || key.equals(""))
        throw new IllegalArgumentException("Null or empty item name");
      if (!(key instanceof String)) {
        throw new ArrayStoreException("Item name is not string: " + key);
        // This can happen because of erasure.  The particular
        // exception is a historical artifact - an implementation
        // detail that leaked into the API.
      }
      map.put((String) key, items.get(key));
    }
    return map;
  }
Beispiel #12
0
 private void writeGenerators(RIFFWriter writer, Map<Integer, Short> generators)
     throws IOException {
   Short keyrange = (Short) generators.get(SF2Region.GENERATOR_KEYRANGE);
   Short velrange = (Short) generators.get(SF2Region.GENERATOR_VELRANGE);
   if (keyrange != null) {
     writer.writeUnsignedShort(SF2Region.GENERATOR_KEYRANGE);
     writer.writeShort(keyrange);
   }
   if (velrange != null) {
     writer.writeUnsignedShort(SF2Region.GENERATOR_VELRANGE);
     writer.writeShort(velrange);
   }
   for (Map.Entry<Integer, Short> generator : generators.entrySet()) {
     if (generator.getKey() == SF2Region.GENERATOR_KEYRANGE) continue;
     if (generator.getKey() == SF2Region.GENERATOR_VELRANGE) continue;
     writer.writeUnsignedShort(generator.getKey());
     writer.writeShort(generator.getValue());
   }
 }
Beispiel #13
0
  /*
   * Returns a keystore entry alias and a single target keystore.
   * An alias prefix must be supplied.
   */
  private AbstractMap.SimpleEntry<String, AbstractMap.SimpleEntry<String, KeyStore>>
      getKeystoreForWriting(String alias) {

    String[] splits = alias.split(this.entryNameSeparator, 2);
    if (splits.length == 2) { // prefixed alias
      KeyStore keystore = keystores.get(splits[0]);
      if (keystore != null) {
        return new AbstractMap.SimpleEntry<>(
            splits[1], new AbstractMap.SimpleEntry<>(splits[0], keystore));
      }
    }
    return null;
  }
Beispiel #14
0
  /**
   * Retrieves the number of entries in this keystore.
   *
   * @return the number of entries in this keystore
   */
  public int engineSize() {

    int size = 0;
    try {
      for (KeyStore keystore : keystores.values()) {
        size += keystore.size();
      }
    } catch (KeyStoreException e) {
      throw new IllegalStateException(e);
    }

    return size;
  }
Beispiel #15
0
  /**
   * Initialize this <code>LoginModule</code>.
   *
   * <p>
   *
   * @param subject the <code>Subject</code> to be authenticated.
   *     <p>
   * @param callbackHandler a <code>CallbackHandler</code> for communicating with the end user
   *     (prompting for usernames and passwords, for example).
   *     <p>
   * @param sharedState shared <code>LoginModule</code> state.
   *     <p>
   * @param options options specified in the login <code>Configuration</code> for this particular
   *     <code>LoginModule</code>.
   */
  public void initialize(
      Subject subject,
      CallbackHandler callbackHandler,
      Map<String, ?> sharedState,
      Map<String, ?> options) {

    this.subject = subject;
    this.callbackHandler = callbackHandler;
    this.sharedState = sharedState;
    this.options = options;

    // initialize any configured options
    debug = "true".equalsIgnoreCase((String) options.get("debug"));
  }
Beispiel #16
0
  boolean setConnectorArg(String name, String value) {
    /*
     * Too late if the connection already made
     */
    if (vm != null) {
      return false;
    }

    Connector.Argument argument = connectorArgs.get(name);
    if (argument == null) {
      return false;
    }
    argument.setValue(value);
    return true;
  }
Beispiel #17
0
  /**
   * Returns the (alias) name of the first keystore entry whose certificate matches the given
   * certificate.
   *
   * <p>This method attempts to match the given certificate with each keystore entry. If the entry
   * being considered is a <i>trusted certificate entry</i>, the given certificate is compared to
   * that entry's certificate. If the entry being considered is a <i>key entry</i>, the given
   * certificate is compared to the first element of that entry's certificate chain (if a chain
   * exists).
   *
   * @param cert the certificate to match with.
   * @return the (alias) name of the first entry with matching certificate, or null if no such entry
   *     exists in this keystore.
   */
  public String engineGetCertificateAlias(Certificate cert) {

    try {

      String alias = null;
      for (KeyStore keystore : keystores.values()) {
        if ((alias = keystore.getCertificateAlias(cert)) != null) {
          break;
        }
      }
      return alias;

    } catch (KeyStoreException e) {
      throw new IllegalStateException(e);
    }
  }
Beispiel #18
0
  /**
   * Lists all the alias names of this keystore.
   *
   * @return enumeration of the alias names
   */
  public Enumeration<String> engineAliases() {
    final Iterator<Map.Entry<String, KeyStore>> iterator = keystores.entrySet().iterator();

    return new Enumeration<String>() {
      private int index = 0;
      private Map.Entry<String, KeyStore> keystoresEntry = null;
      private String prefix = null;
      private Enumeration<String> aliases = null;

      public boolean hasMoreElements() {
        try {
          if (aliases == null) {
            if (iterator.hasNext()) {
              keystoresEntry = iterator.next();
              prefix = keystoresEntry.getKey() + entryNameSeparator;
              aliases = keystoresEntry.getValue().aliases();
            } else {
              return false;
            }
          }
          if (aliases.hasMoreElements()) {
            return true;
          } else {
            if (iterator.hasNext()) {
              keystoresEntry = iterator.next();
              prefix = keystoresEntry.getKey() + entryNameSeparator;
              aliases = keystoresEntry.getValue().aliases();
            } else {
              return false;
            }
          }
        } catch (KeyStoreException e) {
          return false;
        }

        return aliases.hasMoreElements();
      }

      public String nextElement() {
        if (hasMoreElements()) {
          return prefix + aliases.nextElement();
        }
        throw new NoSuchElementException();
      }
    };
  }
Beispiel #19
0
  /**
   * Converts the map of year to month lengths ranging from minYear to maxYear into a linear
   * contiguous array of epochDays. The index is the hijrahMonth computed from year and month and
   * offset by minYear. The value of each entry is the epochDay corresponding to the first day of
   * the month.
   *
   * @param minYear The minimum year for which data is provided
   * @param maxYear The maximum year for which data is provided
   * @param years a Map of year to the array of 12 month lengths
   * @return array of epochDays for each month from min to max
   */
  private int[] createEpochMonths(
      int epochDay, int minYear, int maxYear, Map<Integer, int[]> years) {
    // Compute the size for the array of dates
    int numMonths = (maxYear - minYear + 1) * 12 + 1;

    // Initialize the running epochDay as the corresponding ISO Epoch day
    int epochMonth = 0; // index into array of epochMonths
    int[] epochMonths = new int[numMonths];
    minMonthLength = Integer.MAX_VALUE;
    maxMonthLength = Integer.MIN_VALUE;

    // Only whole years are valid, any zero's in the array are illegal
    for (int year = minYear; year <= maxYear; year++) {
      int[] months = years.get(year); // must not be gaps
      for (int month = 0; month < 12; month++) {
        int length = months[month];
        epochMonths[epochMonth++] = epochDay;

        if (length < 29 || length > 32) {
          throw new IllegalArgumentException("Invalid month length in year: " + minYear);
        }
        epochDay += length;
        minMonthLength = Math.min(minMonthLength, length);
        maxMonthLength = Math.max(maxMonthLength, length);
      }
    }

    // Insert the final epochDay
    epochMonths[epochMonth++] = epochDay;

    if (epochMonth != epochMonths.length) {
      throw new IllegalStateException(
          "Did not fill epochMonths exactly: ndx = "
              + epochMonth
              + " should be "
              + epochMonths.length);
    }

    return epochMonths;
  }
Beispiel #20
0
  @Override
  public void engineStore(KeyStore.LoadStoreParameter param)
      throws IOException, NoSuchAlgorithmException, CertificateException {
    if (param instanceof DomainLoadStoreParameter) {
      DomainLoadStoreParameter domainParameter = (DomainLoadStoreParameter) param;
      List<KeyStoreBuilderComponents> builders =
          getBuilders(domainParameter.getConfiguration(), domainParameter.getProtectionParams());

      for (KeyStoreBuilderComponents builder : builders) {

        try {

          KeyStore.ProtectionParameter pp = builder.protection;
          if (!(pp instanceof KeyStore.PasswordProtection)) {
            throw new KeyStoreException(
                new IllegalArgumentException(
                    "ProtectionParameter" + " must be a KeyStore.PasswordProtection"));
          }
          char[] password = ((KeyStore.PasswordProtection) builder.protection).getPassword();

          // Store the keystores
          KeyStore keystore = keystores.get(builder.name);

          try (FileOutputStream stream = new FileOutputStream(builder.file)) {

            keystore.store(stream, password);
          }
        } catch (KeyStoreException e) {
          throw new IOException(e);
        }
      }
    } else {
      throw new UnsupportedOperationException(
          "This keystore must be stored using a " + "DomainLoadStoreParameter");
    }
  }
Beispiel #21
0
 /** Flush the image cache. */
 static void flushImageCache() {
   imageRefs.clear();
 }
Beispiel #22
0
  /*
   * Parse a keystore domain configuration file and associated collection
   * of keystore passwords to create a collection of KeyStore.Builder.
   */
  private List<KeyStoreBuilderComponents> getBuilders(
      URI configuration, Map<String, KeyStore.ProtectionParameter> passwords) throws IOException {

    PolicyParser parser = new PolicyParser(true); // expand properties
    Collection<PolicyParser.DomainEntry> domains = null;
    List<KeyStoreBuilderComponents> builders = new ArrayList<>();
    String uriDomain = configuration.getFragment();

    try (InputStreamReader configurationReader =
        new InputStreamReader(PolicyUtil.getInputStream(configuration.toURL()), "UTF-8")) {
      parser.read(configurationReader);
      domains = parser.getDomainEntries();

    } catch (MalformedURLException mue) {
      throw new IOException(mue);

    } catch (PolicyParser.ParsingException pe) {
      throw new IOException(pe);
    }

    for (PolicyParser.DomainEntry domain : domains) {
      Map<String, String> domainProperties = domain.getProperties();

      if (uriDomain != null && (!uriDomain.equalsIgnoreCase(domain.getName()))) {
        continue; // skip this domain
      }

      if (domainProperties.containsKey(ENTRY_NAME_SEPARATOR)) {
        this.entryNameSeparator = domainProperties.get(ENTRY_NAME_SEPARATOR);
        // escape any regex meta characters
        char ch = 0;
        StringBuilder s = new StringBuilder();
        for (int i = 0; i < this.entryNameSeparator.length(); i++) {
          ch = this.entryNameSeparator.charAt(i);
          if (REGEX_META.indexOf(ch) != -1) {
            s.append('\\');
          }
          s.append(ch);
        }
        this.entryNameSeparatorRegEx = s.toString();
      }

      Collection<PolicyParser.KeyStoreEntry> keystores = domain.getEntries();
      for (PolicyParser.KeyStoreEntry keystore : keystores) {
        String keystoreName = keystore.getName();
        Map<String, String> properties = new HashMap<>(domainProperties);
        properties.putAll(keystore.getProperties());

        String keystoreType = DEFAULT_KEYSTORE_TYPE;
        if (properties.containsKey(KEYSTORE_TYPE)) {
          keystoreType = properties.get(KEYSTORE_TYPE);
        }

        Provider keystoreProvider = null;
        if (properties.containsKey(KEYSTORE_PROVIDER_NAME)) {
          String keystoreProviderName = properties.get(KEYSTORE_PROVIDER_NAME);
          keystoreProvider = Security.getProvider(keystoreProviderName);
          if (keystoreProvider == null) {
            throw new IOException("Error locating JCE provider: " + keystoreProviderName);
          }
        }

        File keystoreFile = null;
        if (properties.containsKey(KEYSTORE_URI)) {
          String uri = properties.get(KEYSTORE_URI);

          try {
            if (uri.startsWith("file://")) {
              keystoreFile = new File(new URI(uri));
            } else {
              keystoreFile = new File(uri);
            }

          } catch (URISyntaxException | IllegalArgumentException e) {
            throw new IOException(
                "Error processing keystore property: " + "keystoreURI=\"" + uri + "\"", e);
          }
        }

        KeyStore.ProtectionParameter keystoreProtection = null;
        if (passwords.containsKey(keystoreName)) {
          keystoreProtection = passwords.get(keystoreName);

        } else if (properties.containsKey(KEYSTORE_PASSWORD_ENV)) {
          String env = properties.get(KEYSTORE_PASSWORD_ENV);
          String pwd = System.getenv(env);
          if (pwd != null) {
            keystoreProtection = new KeyStore.PasswordProtection(pwd.toCharArray());
          } else {
            throw new IOException(
                "Error processing keystore property: " + "keystorePasswordEnv=\"" + env + "\"");
          }
        } else {
          keystoreProtection = new KeyStore.PasswordProtection(null);
        }

        builders.add(
            new KeyStoreBuilderComponents(
                keystoreName, keystoreType, keystoreProvider, keystoreFile, keystoreProtection));
      }
      break; // skip other domains
    }
    if (builders.isEmpty()) {
      throw new IOException("Error locating domain configuration data " + "for: " + configuration);
    }

    return builders;
  }
Beispiel #23
0
  /**
   * Loads and processes the Hijrah calendar properties file for this calendarType. The starting
   * Hijrah date and the corresponding ISO date are extracted and used to calculate the epochDate
   * offset. The version number is identified and ignored. Everything else is the data for a year
   * with containing the length of each of 12 months.
   *
   * @throws DateTimeException if initialization of the calendar data from the resource fails
   */
  private void loadCalendarData() {
    try {
      String resourceName = calendarProperties.getProperty(PROP_PREFIX + typeId);
      Objects.requireNonNull(
          resourceName, "Resource missing for calendar: " + PROP_PREFIX + typeId);
      Properties props = readConfigProperties(resourceName);

      Map<Integer, int[]> years = new HashMap<>();
      int minYear = Integer.MAX_VALUE;
      int maxYear = Integer.MIN_VALUE;
      String id = null;
      String type = null;
      String version = null;
      int isoStart = 0;
      for (Map.Entry<Object, Object> entry : props.entrySet()) {
        String key = (String) entry.getKey();
        switch (key) {
          case KEY_ID:
            id = (String) entry.getValue();
            break;
          case KEY_TYPE:
            type = (String) entry.getValue();
            break;
          case KEY_VERSION:
            version = (String) entry.getValue();
            break;
          case KEY_ISO_START:
            {
              int[] ymd = parseYMD((String) entry.getValue());
              isoStart = (int) LocalDate.of(ymd[0], ymd[1], ymd[2]).toEpochDay();
              break;
            }
          default:
            try {
              // Everything else is either a year or invalid
              int year = Integer.valueOf(key);
              int[] months = parseMonths((String) entry.getValue());
              years.put(year, months);
              maxYear = Math.max(maxYear, year);
              minYear = Math.min(minYear, year);
            } catch (NumberFormatException nfe) {
              throw new IllegalArgumentException("bad key: " + key);
            }
        }
      }

      if (!getId().equals(id)) {
        throw new IllegalArgumentException("Configuration is for a different calendar: " + id);
      }
      if (!getCalendarType().equals(type)) {
        throw new IllegalArgumentException(
            "Configuration is for a different calendar type: " + type);
      }
      if (version == null || version.isEmpty()) {
        throw new IllegalArgumentException("Configuration does not contain a version");
      }
      if (isoStart == 0) {
        throw new IllegalArgumentException("Configuration does not contain a ISO start date");
      }

      // Now create and validate the array of epochDays indexed by epochMonth
      hijrahStartEpochMonth = minYear * 12;
      minEpochDay = isoStart;
      hijrahEpochMonthStartDays = createEpochMonths(minEpochDay, minYear, maxYear, years);
      maxEpochDay = hijrahEpochMonthStartDays[hijrahEpochMonthStartDays.length - 1];

      // Compute the min and max year length in days.
      for (int year = minYear; year < maxYear; year++) {
        int length = getYearLength(year);
        minYearLength = Math.min(minYearLength, length);
        maxYearLength = Math.max(maxYearLength, length);
      }
    } catch (Exception ex) {
      // Log error and throw a DateTimeException
      PlatformLogger logger = PlatformLogger.getLogger("j86.java.time.chrono");
      logger.severe("Unable to initialize Hijrah calendar proxy: " + typeId, ex);
      throw new DateTimeException("Unable to initialize HijrahCalendar: " + typeId, ex);
    }
  }
Beispiel #24
0
  private Map<String, j86.com.sun.jdi.connect.Connector.Argument> parseConnectorArgs(
      Connector connector, String argString) {
    Map<String, j86.com.sun.jdi.connect.Connector.Argument> arguments =
        connector.defaultArguments();

    /*
     * We are parsing strings of the form:
     *    name1=value1,[name2=value2,...]
     * However, the value1...valuen substrings may contain
     * embedded comma(s), so make provision for quoting inside
     * the value substrings. (Bug ID 4285874)
     */
    String regexPattern =
        "(quote=[^,]+,)|"
            + // special case for quote=.,
            "(\\w+=)"
            + // name=
            "(((\"[^\"]*\")|"
            + //   ( "l , ue"
            "('[^']*')|"
            + //     'l , ue'
            "([^,'\"]+))+,)"; //     v a l u e )+ ,
    Pattern p = Pattern.compile(regexPattern);
    Matcher m = p.matcher(argString);
    while (m.find()) {
      int startPosition = m.start();
      int endPosition = m.end();
      if (startPosition > 0) {
        /*
         * It is an error if parsing skips over any part of argString.
         */
        throw new IllegalArgumentException(
            MessageOutput.format("Illegal connector argument", argString));
      }

      String token = argString.substring(startPosition, endPosition);
      int index = token.indexOf('=');
      String name = token.substring(0, index);
      String value = token.substring(index + 1, token.length() - 1); // Remove comma delimiter

      /*
       * for values enclosed in quotes (single and/or double quotes)
       * strip off enclosing quote chars
       * needed for quote enclosed delimited substrings
       */
      if (name.equals("options")) {
        StringBuilder sb = new StringBuilder();
        for (String s : splitStringAtNonEnclosedWhiteSpace(value)) {
          while (isEnclosed(s, "\"") || isEnclosed(s, "'")) {
            s = s.substring(1, s.length() - 1);
          }
          sb.append(s);
          sb.append(" ");
        }
        value = sb.toString();
      }

      Connector.Argument argument = arguments.get(name);
      if (argument == null) {
        throw new IllegalArgumentException(
            MessageOutput.format(
                "Argument is not defined for connector:", new Object[] {name, connector.name()}));
      }
      argument.setValue(value);

      argString = argString.substring(endPosition); // Remove what was just parsed...
      m = p.matcher(argString); //    and parse again on what is left.
    }
    if ((!argString.equals(",")) && (argString.length() > 0)) {
      /*
       * It is an error if any part of argString is left over,
       * unless it was empty to begin with.
       */
      throw new IllegalArgumentException(
          MessageOutput.format("Illegal connector argument", argString));
    }
    return arguments;
  }