Index: modules/tools/src/main/java/org/apache/harmony/tools/policytool/model/GrantEntry.java =================================================================== --- modules/tools/src/main/java/org/apache/harmony/tools/policytool/model/GrantEntry.java (revision 686169) +++ modules/tools/src/main/java/org/apache/harmony/tools/policytool/model/GrantEntry.java (working copy) @@ -151,9 +151,13 @@ public String toString() { final StringBuilder stringBuilder = new StringBuilder(); - if ( codeBase != null ) - stringBuilder.append( "CodeBase \"" ).append( codeBase ).append( '"'); - if ( signedBy != null ) + stringBuilder.append( " CodeBase " ); + if ( codeBase != null && codeBase.length() > 0 ) + stringBuilder.append( '"' ).append( codeBase ).append( '"' ); + else + stringBuilder.append( "" ); + + if ( signedBy != null && signedBy.length() > 0 ) stringBuilder.append( stringBuilder.length() > 0 ? ", " : "" ).append( "SignedBy \"" ).append( signedBy ).append( '"' ); for ( final Principal principal : principalList ) Index: modules/tools/src/main/java/org/apache/harmony/tools/policytool/model/Permission.java =================================================================== --- modules/tools/src/main/java/org/apache/harmony/tools/policytool/model/Permission.java (revision 686169) +++ modules/tools/src/main/java/org/apache/harmony/tools/policytool/model/Permission.java (working copy) @@ -109,7 +109,7 @@ final StringBuilder stringBuilder = new StringBuilder( className ); if ( targetName != null && targetName.length() > 0 ) - stringBuilder.append( " \"" ).append( targetName ).append( '"' );; + stringBuilder.append( " \"" ).append( targetName ).append( '"' ); if ( actions != null && actions.length() > 0 ) stringBuilder.append( ", \"" ).append( actions ).append( '"'); if ( signedBy != null && signedBy.length() > 0 ) Index: modules/tools/src/main/java/org/apache/harmony/tools/policytool/model/Principal.java =================================================================== --- modules/tools/src/main/java/org/apache/harmony/tools/policytool/model/Principal.java (revision 686169) +++ modules/tools/src/main/java/org/apache/harmony/tools/policytool/model/Principal.java (working copy) @@ -69,7 +69,7 @@ try { return super.clone(); } catch ( final CloneNotSupportedException cnse ) { - // This is never going to happen. + // This' never gonna happen. cnse.printStackTrace(); return null; } Index: modules/tools/src/main/java/org/apache/harmony/tools/policytool/control/PolicyTextParser.java =================================================================== --- modules/tools/src/main/java/org/apache/harmony/tools/policytool/control/PolicyTextParser.java (revision 686169) +++ modules/tools/src/main/java/org/apache/harmony/tools/policytool/control/PolicyTextParser.java (working copy) @@ -21,9 +21,12 @@ import java.util.List; import org.apache.harmony.tools.policytool.model.CommentEntry; +import org.apache.harmony.tools.policytool.model.GrantEntry; import org.apache.harmony.tools.policytool.model.KeystoreEntry; import org.apache.harmony.tools.policytool.model.KeystorePasswordURLEntry; +import org.apache.harmony.tools.policytool.model.Permission; import org.apache.harmony.tools.policytool.model.PolicyEntry; +import org.apache.harmony.tools.policytool.model.Principal; /** * Policy text parser. @@ -34,128 +37,389 @@ /** String containing the white spaces. */ private static final String WHITE_SPACES = " \t\n\r"; + /** Policy text to be parsed. */ + private final String policyText; + /** Char array of the policy text. */ + private final char[] policyTextChars; + /** The created equivalent list of policy entries. */ + private final List< PolicyEntry > policyEntryList = new ArrayList< PolicyEntry >(); + + /** First and last indices of the current/first token determining the next entry. */ + private int[] firstLastTokenIndices; + /** Position of the parsing. */ + private int index = 0; + /** New position of parsing after the current entry is processed. */ + private int newIndex = -1; + /** - * Parses a policy text and creates an equivalent list of policy entries from it. + * Creates a new PolicyTextParser. * @param policyText policy text to be parsed + */ + public PolicyTextParser( final String policyText ) { + this.policyText = policyText.replace( "\r", "" ); // I only want to handle a unified line terminator + policyTextChars = this.policyText.toCharArray(); + } + + /** + * Parses a policy text and returns an equivalent list of policy entries from it. + * @param policyText policy text to be parsed + * @return an equivalent list of policy entries created from the policy text, equivalent to policy text + * @throws InvalidPolicyTextException thrown if policyText is invalid + */ + public static List< PolicyEntry > parsePolicyText( final String policyText ) throws InvalidPolicyTextException { + return new PolicyTextParser( policyText ).parsePolicyText(); + } + + /** + * Parses the policy text and creates an equivalent list of policy entries from it. * @return an equivalent list of policy entries created from the policy text, equivalent to policy text * @throws InvalidPolicyTextException thrown if policyText is invalid */ - public static List< PolicyEntry > parsePolicyText( String policyText ) throws InvalidPolicyTextException { - policyText = policyText.replace( "\r", "" ); // I only want to handle a unified line terminator + public List< PolicyEntry > parsePolicyText() throws InvalidPolicyTextException { + while ( ( firstLastTokenIndices = peekTokenAheadCommentsIncluded( index ) ) != null ) { + + final String nextToken = policyText.substring( firstLastTokenIndices[ 0 ], firstLastTokenIndices[ 1 ] ); + final String loweredNextToken = nextToken.toLowerCase(); + + // Line comment + if ( nextToken.startsWith( "//" ) ) + parseLineComment(); + + // Block comment + else if ( nextToken.startsWith( "/*" ) ) + parseBlockComment(); + + // Keystore entry + else if ( loweredNextToken.equals( KeystoreEntry.LOWERED_KEYWORD ) ) + parseKeystoreEntry(); + + // Keystore password URL entry + else if ( loweredNextToken.equals( KeystorePasswordURLEntry.LOWERED_KEYWORD ) ) + parseKeystorePasswordURLEntry(); + + // Grant entry + else if ( loweredNextToken.equals( GrantEntry.LOWERED_KEYWORD ) ) + parseGrantEntry(); + + // Couldn't recognize any entry! + else + throw new InvalidPolicyTextException( "Unknown entry: " + nextToken ); + + if ( newIndex >= 0 && newIndex < policyTextChars.length && policyTextChars[ newIndex ] == '\n' ) + newIndex++; + + index = newIndex; + } + + return policyEntryList; + } + + /** + * Parses a line comment. + */ + private void parseLineComment() { + newIndex = policyText.indexOf( '\n', firstLastTokenIndices[ 0 ] + 2 ); + if ( newIndex < 0 ) // This is the last line + newIndex = policyTextChars.length; + policyEntryList.add( new CommentEntry( policyText.substring( index, newIndex ) ) ); + } + + /** + * Parses a block comment. + * @throws InvalidPolicyTextException thrown if closing bracket is missing for block comment + */ + private void parseBlockComment() throws InvalidPolicyTextException { + newIndex = policyText.indexOf( "*/", firstLastTokenIndices[ 0 ] + 2 ); + if ( newIndex < 0 ) // No closing bracket + throw new InvalidPolicyTextException( "No closing bracket for block comment!" ); + newIndex += 2; // length of "*/" + policyEntryList.add( new CommentEntry( policyText.substring( index, newIndex ) ) ); + } + + /** + * Parses a keystore entry.
+ * The keystoer entry syntax: + *
+     * keystore "some_keystore_url", "keystore_type", "keystore_provider";
+     * 
+ * @throws InvalidPolicyTextException thrown if invalid keystore entry syntax is detected + */ + private void parseKeystoreEntry() throws InvalidPolicyTextException { + final int[] keystoreURLIndices = peekQuotedStringAhead( firstLastTokenIndices[ 1 ] ); + if ( keystoreURLIndices == null ) + throw new InvalidPolicyTextException( "Incomplete keystore entry, found no quoted string for keystore URL!" ); - final List< PolicyEntry > policyEntryList = new ArrayList< PolicyEntry >(); + int[] keystoreTypeIndices = null; + int[] keystoreProviderIndices = null; - final char[] policyTextChars = policyText.toCharArray(); + char nextChar = peekNextNonWhiteSpaceChar( keystoreURLIndices[ 1 ] ); + if ( nextChar != PolicyEntry.TERMINATOR_CHAR ) { + if ( nextChar != ',' ) + throw new InvalidPolicyTextException( "Was expecting semicolon but found something else!" ); + keystoreTypeIndices = peekQuotedStringAhead( skipWhiteSpaces( keystoreURLIndices[ 1 ] ) + 1 ); + if ( keystoreTypeIndices == null ) + throw new InvalidPolicyTextException( "Incomplete keystore entry, found no quoted string for keystore type!" ); - int index = 0; - int[] firstLastTokenIndices; - while ( ( firstLastTokenIndices = peekTokenAhead( policyTextChars, index ) ) != null ) { + nextChar = peekNextNonWhiteSpaceChar( keystoreTypeIndices[ 1 ] ); + if ( nextChar != PolicyEntry.TERMINATOR_CHAR ) { + if ( nextChar != ',' ) + throw new InvalidPolicyTextException( "Was expecting semicolon but found something else!" ); + keystoreProviderIndices = peekQuotedStringAhead( skipWhiteSpaces( keystoreTypeIndices[ 1 ] ) + 1 ); + if ( keystoreProviderIndices == null ) + throw new InvalidPolicyTextException( "Incomplete keystore entry, found no quoted string for keystore provider!" ); - final String nextToken = policyText.substring( firstLastTokenIndices[ 0 ], firstLastTokenIndices[ 1 ] ); - final String loweredNextToken = nextToken.toLowerCase(); + if ( peekNextNonWhiteSpaceChar( keystoreProviderIndices[ 1 ] ) != PolicyEntry.TERMINATOR_CHAR ) + throw new InvalidPolicyTextException( "Was expecting semicolon but found something else!" ); + else + newIndex = skipWhiteSpaces( keystoreProviderIndices[ 1 ] ) + 1; + } + else + newIndex = skipWhiteSpaces( keystoreTypeIndices[ 1 ] ) + 1; + } + else + newIndex = skipWhiteSpaces( keystoreURLIndices[ 1 ] ) + 1; + + final KeystoreEntry keystoreEntry = new KeystoreEntry(); + keystoreEntry.setUrl( policyText.substring( keystoreURLIndices[ 0 ] + 1, keystoreURLIndices[ 1 ] - 1 ) ); + if ( keystoreTypeIndices != null ) + keystoreEntry.setType( policyText.substring( keystoreTypeIndices[ 0 ] + 1, keystoreTypeIndices[ 1 ] - 1 ) ); + if ( keystoreProviderIndices != null ) + keystoreEntry.setProvider( policyText.substring( keystoreProviderIndices[ 0 ] + 1, keystoreProviderIndices[ 1 ] - 1 ) ); + policyEntryList.add( keystoreEntry ); + } + + /** + * Parses a keystore password URL entry.
+ * The keystore password URL syntax: + *
+     * keystorePasswordURL "some_password_url";
+     * 
+ * @throws InvalidPolicyTextException thrown if invalid keystore password URL entry syntax is detected + */ + private void parseKeystorePasswordURLEntry() throws InvalidPolicyTextException { + final int[] keystorePasswordURLIndices = peekQuotedStringAhead( firstLastTokenIndices[ 1 ] ); + if ( keystorePasswordURLIndices == null ) + throw new InvalidPolicyTextException( "Incomplete keystore password URL entry, found no quoted string for keystore password URL!" ); + + final char nextChar = peekNextNonWhiteSpaceChar( keystorePasswordURLIndices[ 1 ] ); + if ( nextChar != PolicyEntry.TERMINATOR_CHAR ) + throw new InvalidPolicyTextException( "Was expecting semicolon but found something else!" ); + else + newIndex = skipWhiteSpaces( keystorePasswordURLIndices[ 1 ] ) + 1; + + final KeystorePasswordURLEntry keystorePasswordURLEntry = new KeystorePasswordURLEntry(); + keystorePasswordURLEntry.setUrl( policyText.substring( keystorePasswordURLIndices[ 0 ] + 1, keystorePasswordURLIndices[ 1 ] - 1 ) ); + policyEntryList.add( keystorePasswordURLEntry ); + } + + /** + * Parses a grant entry.
+ * The grant entry syntax: + *
+     * grant signedBy "signer_names", codeBase "URL",
+     *       principal principal_class_name "principal_name",
+     *       principal principal_class_name "principal_name",
+     *       ... {
+     *
+     *     permission permission_class_name "target_name", "action", 
+     *         signedBy "signer_names";
+     *     permission permission_class_name "target_name", "action", 
+     *         signedBy "signer_names";
+     *     ...
+     * };
+     * 
+ * @throws InvalidPolicyTextException thrown if invalid grant entry syntax is detected + */ + private void parseGrantEntry() throws InvalidPolicyTextException { + final GrantEntry grantEntry = new GrantEntry(); + + newIndex = firstLastTokenIndices[ 1 ]; + + boolean firstIteration = true; + char nextChar; + // First we parse the grant parameters such as signedBy, codeBase and the principals. + while ( ( nextChar = peekNextNonWhiteSpaceChar( newIndex ) ) != '{' ) { + + if ( firstIteration ) + firstIteration = false; + else + if ( nextChar != ',' ) + throw new InvalidPolicyTextException( "Was expecting comma but found something else!" ); + else + newIndex = skipWhiteSpaces( newIndex ) + 1; + + final int[] paramNameIndices = peekTokenAhead( newIndex ); + if ( paramNameIndices == null ) + throw new InvalidPolicyTextException( "Incomplete grant entry!" ); + final String loweredParamName = policyText.substring( paramNameIndices[ 0 ], paramNameIndices[ 1 ] ).toLowerCase(); + + if ( loweredParamName.equals( "signedby" ) ) { + final int[] paramValueIndices = peekQuotedStringAhead( paramNameIndices[ 1 ] ); + if ( paramValueIndices == null ) + throw new InvalidPolicyTextException( "Incomplete keystore entry, found no quoted string for signedBy!" ); + if ( grantEntry.getSignedBy() != null ) + throw new InvalidPolicyTextException( "Invalid keystore entry, only 1 signedBy allowed!" ); + if ( grantEntry.getCodeBase() != null || !grantEntry.getPrincipalList().isEmpty() ) + throw new InvalidPolicyTextException( "Invalid keystore entry, signedBy cannot be after codeBase or principals!" ); + grantEntry.setSignedBy( policyText.substring( paramValueIndices[ 0 ] + 1, paramValueIndices[ 1 ] - 1 ) ); + newIndex = paramValueIndices[ 1 ]; + } + else if ( loweredParamName.equals( "codebase" ) ) { + final int[] firstLastParamValueIndices = peekQuotedStringAhead( paramNameIndices[ 1 ] ); + if ( firstLastParamValueIndices == null ) + throw new InvalidPolicyTextException( "Incomplete keystore entry, found no quoted string for codeBase!" ); + if ( grantEntry.getCodeBase() != null ) + throw new InvalidPolicyTextException( "Invalid keystore entry, only 1 codeBase allowed!" ); + if ( !grantEntry.getPrincipalList().isEmpty() ) + throw new InvalidPolicyTextException( "Invalid keystore entry, signedBy cannot be after principals!" ); + grantEntry.setCodeBase( policyText.substring( firstLastParamValueIndices[ 0 ] + 1, firstLastParamValueIndices[ 1 ] - 1 ) ); + newIndex = firstLastParamValueIndices[ 1 ]; + } + else if ( loweredParamName.equals( "principal" ) ) { + final int[] classNameIndices = peekTokenAhead( paramNameIndices[ 1 ] ); + if ( classNameIndices == null || policyTextChars[ classNameIndices[ 0 ] ] == '{' ) + throw new InvalidPolicyTextException( "Invalid grant entry, found no class name for principal!" ); + + final int[] principalNameIndices = peekQuotedStringAhead( classNameIndices[ 1 ] ); + if ( principalNameIndices == null ) + throw new InvalidPolicyTextException( "Invalid grant entry, found no name for principal!" ); - int newIndex = -1; + final Principal principal = new Principal(); + principal.setType( policyText.substring( classNameIndices[ 0 ], classNameIndices[ 1 ] ) ); + principal.setName( policyText.substring( principalNameIndices[ 0 ] + 1, principalNameIndices[ 1 ] - 1 ) ); + grantEntry.getPrincipalList().add( principal ); - // Line comment - if ( nextToken.startsWith( "//" ) ) { - newIndex = policyText.indexOf( '\n', firstLastTokenIndices[ 1 ] ); - if ( newIndex < 0 ) // This is the last line - newIndex = policyTextChars.length; - policyEntryList.add( new CommentEntry( policyText.substring( index, newIndex ) ) ); + newIndex = principalNameIndices[ 1 ]; } + } - // Block comment - else if ( nextToken.startsWith( "/*" ) ) { - newIndex = policyText.indexOf( "*/", firstLastTokenIndices[ 1 ] ); - if ( newIndex < 0 ) // No closing bracket - throw new InvalidPolicyTextException( "No closing bracket for block comment!" ); - newIndex += 2; // length of "*/" - policyEntryList.add( new CommentEntry( policyText.substring( index, newIndex ) ) ); + newIndex = policyText.indexOf( '{', newIndex ) + 1; + + // Now permissions what we have left + while ( ( nextChar = peekNextNonWhiteSpaceChar( newIndex ) ) != '}' ) { + + final int[] keywordIndices = peekTokenAhead( newIndex ); + if ( keywordIndices == null ) + throw new InvalidPolicyTextException( "Incomplete grant entry!" ); + final String loweredKeyword = policyText.substring( keywordIndices[ 0 ], keywordIndices[ 1 ] ).toLowerCase(); + + if ( !loweredKeyword.equals( "permission" ) ) + throw new InvalidPolicyTextException( "Incomplete grant entry, was expecting permission but found something else!" ); + + final int[] classNameIndices = peekTokenAhead( keywordIndices[ 1 ] ); + if ( classNameIndices == null || policyTextChars[ classNameIndices[ 0 ] ] == '}' ) + throw new InvalidPolicyTextException( "Invalid grant entry, found no class name for permission!" ); + if ( classNameIndices[ 1 ] - classNameIndices[ 0 ] == 0 ) { + if ( policyTextChars[ classNameIndices[ 0 ] ] == ',' || policyTextChars[ classNameIndices[ 0 ] ] == PolicyEntry.TERMINATOR_CHAR ) // Class name is only a comma or a semicolon + throw new InvalidPolicyTextException( "Invalid grant entry, found no class name for permission!" ); + } + else { + if ( policyTextChars[ classNameIndices[ 1 ] - 1 ] == ',' || policyTextChars[ classNameIndices[ 1 ] - 1 ] == PolicyEntry.TERMINATOR_CHAR ) + classNameIndices[ 1 ]--; // Class name is more than 1 character long and comma or semicolon is at its end; we step back from it } - // Keystore entry - else if ( loweredNextToken.equals( KeystoreEntry.LOWERED_KEYWORD ) ) { - final int[] firstLastKeystoreURLIndices = peekQuotedStringAhead( policyTextChars, firstLastTokenIndices[ 1 ] ); - if ( firstLastKeystoreURLIndices == null ) - throw new InvalidPolicyTextException( "Incomplete keystore entry, found no quoted string for keystore URL!" ); + int[] targetNameIndices = null; + int[] actionsIndices = null; + int[] signedByIndices = null; - int[] keystoreTypeIndices = null; - int[] keystoreProviderIndices = null; + nextChar = peekNextNonWhiteSpaceChar( classNameIndices[ 1 ] ); + if ( nextChar != PolicyEntry.TERMINATOR_CHAR ) { + if ( nextChar != ',' ) { + // There must be a target name here! + targetNameIndices = peekQuotedStringAhead( classNameIndices[ 1 ] ); + if ( targetNameIndices == null ) + throw new InvalidPolicyTextException( "Invalid grant entry, found no name for permission!" ); + } - char nextChar = peekNextNonWhiteSpaceChar( policyTextChars, firstLastKeystoreURLIndices[ 1 ] ); + newIndex = targetNameIndices == null ? classNameIndices[ 1 ] : targetNameIndices[ 1 ]; + nextChar = peekNextNonWhiteSpaceChar( newIndex ); if ( nextChar != PolicyEntry.TERMINATOR_CHAR ) { if ( nextChar != ',' ) throw new InvalidPolicyTextException( "Was expecting semicolon but found something else!" ); - keystoreTypeIndices = peekQuotedStringAhead( policyTextChars, policyText.indexOf( ',', firstLastKeystoreURLIndices[ 1 ] ) + 1 ); - if ( keystoreTypeIndices == null ) - throw new InvalidPolicyTextException( "Incomplete keystore entry, found no quoted string for keystore type!" ); + + newIndex = skipWhiteSpaces( newIndex ); + nextChar = peekNextNonWhiteSpaceChar( newIndex + 1 ); + if ( nextChar == '"' ) { // actions are specified + actionsIndices = peekQuotedStringAhead( newIndex + 1 ); + if ( actionsIndices == null ) + throw new InvalidPolicyTextException( "Incomplete keystore entry, found no quoted string for permission actions!" ); + newIndex = actionsIndices[ 1 ]; + } - nextChar = peekNextNonWhiteSpaceChar( policyTextChars, keystoreTypeIndices[ 1 ] ); + nextChar = peekNextNonWhiteSpaceChar( newIndex ); if ( nextChar != PolicyEntry.TERMINATOR_CHAR ) { if ( nextChar != ',' ) throw new InvalidPolicyTextException( "Was expecting semicolon but found something else!" ); - keystoreProviderIndices = peekQuotedStringAhead( policyTextChars, policyText.indexOf( ',', keystoreTypeIndices[ 1 ] ) + 1 ); - if ( keystoreProviderIndices == null ) - throw new InvalidPolicyTextException( "Incomplete keystore entry, found no quoted string for keystore provider!" ); + final int[] signedByKeywordIndices = peekTokenAhead( skipWhiteSpaces( newIndex ) + 1 ); + final String loweredSignedByKeyword = policyText.substring( signedByKeywordIndices[ 0 ], signedByKeywordIndices[ 1 ] ).toLowerCase(); - if ( peekNextNonWhiteSpaceChar( policyTextChars, keystoreProviderIndices[ 1 ] ) != PolicyEntry.TERMINATOR_CHAR ) + if ( !loweredSignedByKeyword.equals( "signedby" ) ) + throw new InvalidPolicyTextException( "Incomplete grant entry, was expecting signedBy but found something else!" ); + + signedByIndices = peekQuotedStringAhead( signedByKeywordIndices[ 1 ] ); + if ( signedByIndices == null ) + throw new InvalidPolicyTextException( "Incomplete keystore entry, found no quoted string for permission signedBy!" ); + + if ( peekNextNonWhiteSpaceChar( signedByIndices[ 1 ] ) != PolicyEntry.TERMINATOR_CHAR ) throw new InvalidPolicyTextException( "Was expecting semicolon but found something else!" ); else - newIndex = policyText.indexOf( PolicyEntry.TERMINATOR_CHAR, keystoreProviderIndices[ 1 ] ) + 1; + newIndex = skipWhiteSpaces( newIndex ) + 1; } else - newIndex = policyText.indexOf( PolicyEntry.TERMINATOR_CHAR, keystoreTypeIndices[ 1 ] ) + 1; + newIndex = skipWhiteSpaces( newIndex ) + 1; } else - newIndex = policyText.indexOf( PolicyEntry.TERMINATOR_CHAR, firstLastKeystoreURLIndices[ 1 ] ) + 1; - - final KeystoreEntry keystoreEntry = new KeystoreEntry(); - keystoreEntry.setUrl( policyText.substring( firstLastKeystoreURLIndices[ 0 ] + 1, firstLastKeystoreURLIndices[ 1 ] - 1 ) ); - if ( keystoreTypeIndices != null ) - keystoreEntry.setType( policyText.substring( keystoreTypeIndices[ 0 ] + 1, keystoreTypeIndices[ 1 ] - 1 ) ); - if ( keystoreProviderIndices != null ) - keystoreEntry.setProvider( policyText.substring( keystoreProviderIndices[ 0 ] + 1, keystoreProviderIndices[ 1 ] - 1 ) ); - policyEntryList.add( keystoreEntry ); + newIndex = skipWhiteSpaces( newIndex ) + 1; } + else + newIndex = skipWhiteSpaces( classNameIndices[ 1 ] ) + 1; - // Keystore password URL entry - else if ( loweredNextToken.equals( KeystorePasswordURLEntry.LOWERED_KEYWORD ) ) { - final int[] firstLastKeystorePasswordURLIndices = peekQuotedStringAhead( policyTextChars, firstLastTokenIndices[ 1 ] ); - if ( firstLastKeystorePasswordURLIndices == null ) - throw new InvalidPolicyTextException( "Incomplete keystore password URL entry, found no quoted string for keystore password URL!" ); - - final char nextChar = peekNextNonWhiteSpaceChar( policyTextChars, firstLastKeystorePasswordURLIndices[ 1 ] ); - if ( nextChar != PolicyEntry.TERMINATOR_CHAR ) - throw new InvalidPolicyTextException( "Was expecting semicolon but found something else!" ); - else - newIndex = policyText.indexOf( PolicyEntry.TERMINATOR_CHAR, firstLastKeystorePasswordURLIndices[ 1 ] ) + 1; - - final KeystorePasswordURLEntry keystorePasswordURLEntry = new KeystorePasswordURLEntry(); - keystorePasswordURLEntry.setUrl( policyText.substring( firstLastKeystorePasswordURLIndices[ 0 ] + 1, firstLastKeystorePasswordURLIndices[ 1 ] - 1 ) ); - policyEntryList.add( keystorePasswordURLEntry ); - } - - if ( newIndex >= 0 && newIndex < policyTextChars.length && policyTextChars[ newIndex ] == '\n' ) - newIndex++; + final Permission permission = new Permission(); + permission.setClassName( policyText.substring( classNameIndices[ 0 ], classNameIndices[ 1 ] ) ); + if ( targetNameIndices != null ) + permission.setTargetName( policyText.substring( targetNameIndices[ 0 ] + 1, targetNameIndices[ 1 ] - 1 ) ); + if ( actionsIndices != null ) + permission.setActions( policyText.substring( actionsIndices[ 0 ] + 1, actionsIndices[ 1 ] - 1 ) ); + if ( signedByIndices != null ) + permission.setSignedBy( policyText.substring( signedByIndices[ 0 ] + 1, signedByIndices[ 1 ] - 1 ) ); + grantEntry.getPermissionList().add( permission ); + } - index = newIndex; - } + newIndex = skipWhiteSpaces( newIndex ) + 1; // index of '}' + 1 (comments skipped) + if ( peekNextNonWhiteSpaceChar( newIndex ) != PolicyEntry.TERMINATOR_CHAR ) + throw new InvalidPolicyTextException( "Was expecting semicolon but found something else!" ); + newIndex = skipWhiteSpaces( newIndex ) + 1; - return policyEntryList; + policyEntryList.add( grantEntry ); } /** - * Skips the following whtie spaces starting from the specified index, + * Skips the following white spaces starting from the specified index, * and returns the next non-white space index or -1 if end of string reached. + * Comments are skipped over if found. * - * @param stringChars char array of the string to use * @param index index to start from * @return the next non-white space index or -1 if end of string reached */ - private static int skipWhiteSpaces( final char[] stringChars, int index ) { + private int skipWhiteSpaces( int index ) { try { - while ( WHITE_SPACES.indexOf( stringChars[ index ] ) >= 0 ) - index++; + boolean foundComment; + do { + foundComment = false; + while ( WHITE_SPACES.indexOf( policyTextChars[ index ] ) >= 0 ) + index++; + + if ( policyTextChars[ index ] == '/' && index < policyTextChars.length - 1 ) { + if ( policyTextChars[ index + 1 ] == '/' ) { + foundComment = true; + index = policyText.indexOf( '\n', index + 2 ) + 1; + } + else if ( policyTextChars[ index + 1 ] == '*' ) { + foundComment = true; + index = policyText.indexOf( "*/", index + 2 ) + 2; + } + } + } while ( foundComment ); // If foundComment, we have to recheck, because another comment might follow the the one we just found return index; } catch ( final ArrayIndexOutOfBoundsException aioobe ) { @@ -165,16 +429,16 @@ /** * Returns the first non-whitespace character starting from a given index or -1 if all the remaining characters are white spaces. - * @param stringChars char array of the string to use + * Comments are skipped over if found. * @param index index to start from * @return the first non-whitespace character starting from a given index or -1 if all the remaining characters are white spaces */ - private static char peekNextNonWhiteSpaceChar( final char[] stringChars, int index ) { - index = skipWhiteSpaces( stringChars, index ); + private char peekNextNonWhiteSpaceChar( int index ) { + index = skipWhiteSpaces( index ); if ( index < 0 ) return (char) -1; else - return stringChars[ index ]; + return policyTextChars[ index ]; } /** @@ -179,12 +443,12 @@ /** * Returns the first (inclusive) and last index (exclusive) of the next token or null if no more tokens. - * @param stringChars char array of the string to use + * Comments are skipped over if found. * @param index index to start from * @return the first (inclusive) and last index (exclusive) of the next token or null if no more tokens */ - private static int[] peekTokenAhead ( final char[] stringChars, int index ) { - index = skipWhiteSpaces( stringChars, index ); + private int[] peekTokenAhead ( int index ) { + index = skipWhiteSpaces( index ); if ( index < 0 ) return null; @@ -190,8 +454,8 @@ final int firstIndex = index; - while ( index++ < stringChars.length ) - if ( index == stringChars.length || WHITE_SPACES.indexOf( stringChars[ index ] ) >= 0 ) + while ( index++ < policyTextChars.length ) + if ( index == policyTextChars.length || WHITE_SPACES.indexOf( policyTextChars[ index ] ) >= 0 ) break; return new int[] { firstIndex, index }; @@ -200,8 +464,8 @@ /** * Returns the first (inclusive) and last index (exclusive) of the next quoted string or null if found something else.
* The string denoted by the returned indices includes the quotes in the beginning and in the end of the quoted string. + * Comments are skipped over if found. * - * @param stringChars char array of the string to use * @param index index to start from * @return the first (inclusive) and last index (exclusive) of the next quoted string or null if found something else * @throws InvalidPolicyTextException thrown if no quoted string found @@ -206,13 +470,13 @@ * @return the first (inclusive) and last index (exclusive) of the next quoted string or null if found something else * @throws InvalidPolicyTextException thrown if no quoted string found */ - private static int[] peekQuotedStringAhead ( final char[] stringChars, int index ) throws InvalidPolicyTextException { + private int[] peekQuotedStringAhead ( int index ) throws InvalidPolicyTextException { try { - index = skipWhiteSpaces( stringChars, index ); + index = skipWhiteSpaces( index ); if ( index < 0 ) return null; - if ( stringChars[ index ] != '"' ) + if ( policyTextChars[ index ] != '"' ) throw new InvalidPolicyTextException( "Could not find expected quoted string (missing opener quotation mark)!" ); final int firstIndex = index; @@ -217,11 +481,11 @@ final int firstIndex = index; - while ( ++index <= stringChars.length ) { - if ( index == stringChars.length ) + while ( ++index <= policyTextChars.length ) { + if ( index == policyTextChars.length ) throw new InvalidPolicyTextException( "Could not find expected quoted string (missing closer quotation mark)!" ); - if ( stringChars[ index ] == '"' ) + if ( policyTextChars[ index ] == '"' ) break; } @@ -232,4 +496,43 @@ } } + /** + * Skips the following white spaces starting from the specified index, + * and returns the next non-white space index or -1 if end of string reached. + * Comments are not skipped over. + * + * @param index index to start from + * @return the next non-white space index or -1 if end of string reached + */ + private int skipWhiteSpacesCommentsIncluded( int index ) { + try { + while ( WHITE_SPACES.indexOf( policyTextChars[ index ] ) >= 0 ) + index++; + + return index; + } catch ( final ArrayIndexOutOfBoundsException aioobe ) { + return -1; + } + } + + /** + * Returns the first (inclusive) and last index (exclusive) of the next token or null if no more tokens. + * Comments are not skipped over. + * @param index index to start from + * @return the first (inclusive) and last index (exclusive) of the next token or null if no more tokens + */ + private int[] peekTokenAheadCommentsIncluded( int index ) { + index = skipWhiteSpacesCommentsIncluded( index ); + if ( index < 0 ) + return null; + + final int firstIndex = index; + + while ( index++ < policyTextChars.length ) + if ( index == policyTextChars.length || WHITE_SPACES.indexOf( policyTextChars[ index ] ) >= 0 ) + break; + + return new int[] { firstIndex, index }; + } + }