class RequireOsgiCompatibleVersionRule implements EnforcerRule {

    public void ensureValidOsgiVersion(String version) throws EnforcerRuleException
    {
        if (version.endsWith("SNAPSHOT"))
        {
            // Skip check on SNAPSHOT versions.
            return;
        }
        
        String parts[] = version.split("\\.");
        if (parts.length > 4)
        {
            throw new EnforcerRuleException("The version \"" + version + "\" does not conform to the OSGi version requirements.  "
                    + "It can't have more than 4 parts (#.#.#.*)" + " - The '.' character has a special meaning");
        }

        if (parts.length < 3)
        {
            throw new EnforcerRuleException("The version \"" + version + "\" does not conform to the OSGi version requirements.  "
                    + "It must have 3 (or 4) parts (#.#.#.*)");
        }

        for (int i = 0; i < 3; i++)
        {
            if (!StringUtils.isNumeric(parts[i]))
            {
                throw new EnforcerRuleException("The version \"" + version + "\" does not conform to the OSGi version requirements.  " + "Part #" + (i + 1)
                        + " \"" + parts[i] + "\" of an OSGi version must be a non-negative number (#.#.#.*).");
            }
            if (Integer.parseInt(parts[i]) < 0)
            {
                throw new EnforcerRuleException("The version \"" + version + "\" does not conform to the OSGi version requirements.  " + "Part #" + (i + 1)
                        + " \"" + parts[i] + "\" of an OSGi version must be a non-negative number (#.#.#.*).");
            }
        }

        if (parts.length == 4)
        {
            for (char c : parts[3].toCharArray())
            {
                if ((c >= '0') && (c <= '9'))
                {
                    continue; // numbers are acceptable
                }
                if ((c >= 'A') && (c <= 'Z'))
                {
                    continue; // upper case letters are acceptable
                }
                if ((c >= 'a') && (c <= 'z'))
                {
                    continue; // lower case letters are acceptable
                }
                if ((c == '-') || (c == '_'))
                {
                    continue; // underscore and dash are also acceptable
                }
                // All other characters are invalid for the qualifier
                throw new EnforcerRuleException("The OSGi qualifier of \"" + version + "\" does not conform to the OSGi version requirements.  " + 
                        "Only Letters (upper and lower), numbers, dash '-', and underscore '_' are allowed.");
            }
        }
    }

}

class RequireOsgiCompatibleVersionRuleTest {

    @Test
    public void testInvalidQualifierOsgiVersion()
        throws EnforcerRuleException
    {

        Assertions.assertThrows( EnforcerRuleException.class, () -> {
            RequireOsgiCompatibleVersionRule rule = new RequireOsgiCompatibleVersionRule();
            rule.ensureValidOsgiVersion( "1.0.2.2009:05:12" );
        } );
    }

}