/* * Copyright (c) Members of the EGEE Collaboration. 2006-2010. * See http://www.eu-egee.org/partners/ for details on the copyright holders. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.glite.authz.pep.obligation.dfpmap; import java.io.IOException; import java.io.LineNumberReader; import java.io.Reader; import java.util.List; import java.util.UnknownFormatConversionException; import org.glite.authz.common.config.ConfigurationException; import org.glite.authz.common.util.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A parser for map files. * * http://dev.globus.org/wiki/Gridmap */ public class DFPMFileParser { /** Class logger. */ private final Logger log = LoggerFactory.getLogger(DFPMFileParser.class); /** * Parses a map file and populates a given DN/FQAN to POSIX map with its content. * * @param map the map to populate * @param mapFileReader reader of the map file * * @throws ConfigurationException thrown if the map file can not be read */ public void parse(final DFPM map, final Reader mapFileReader) throws ConfigurationException { LineNumberReader reader = new LineNumberReader(mapFileReader); try { String line = reader.readLine(); do { parseLine(map, line, reader.getLineNumber()); line = reader.readLine(); } while (line != null); } catch (IOException e) { log.error("Unable to read map file", e); throw new ConfigurationException("Unable to read map file", e); } } /** * Parses a single line in of map file. * * @param map map to populate * @param line the line to parse * @param lineNumber the current line number * * @throws ConfigurationException thrown if the map file contains an invalid mapping entry */ private void parseLine(DFPM map, String line, int lineNumber) throws ConfigurationException { String trimmedLine = Strings.safeTrimOrNullString(line); if (trimmedLine == null || trimmedLine.startsWith("#")) { log.trace("Line number {} is a comment, no processing performed", lineNumber); return; } int lastDQuote = trimmedLine.lastIndexOf("\""); String unescapedKey = Strings.safeTrimOrNullString(trimmedLine.substring(1, lastDQuote)); if (unescapedKey == null) { String msg = "Error on map file line " + lineNumber + ": Map file entry key may not be null or empty"; log.error(msg); throw new ConfigurationException(msg); } String key = unescapeString(unescapedKey); List<String> values = Strings.toList(trimmedLine.substring(++lastDQuote), ","); if (values == null || values.isEmpty()) { String msg = "Error on map file line " + lineNumber + ": Map file entry value may not be null or empty"; log.error(msg); throw new ConfigurationException(msg); } log.debug("Line {}: maps {} to {}", new Object[] { lineNumber, key, values }); map.put(key, values); } /** * Replaces escape sequences in a string. The standard Java escape sequences (b, f, n, r, t, u, \, ', ") are * supported as well as \xXX for hexadecimal character representation. * * @param string the string to unescape * * @return the unescaped string * * @throws UnknownFormatConversionException thrown if an unsupported escape sequence is found */ private String unescapeString(String string) throws UnknownFormatConversionException { char[] stringChars = string.toCharArray(); StringBuilder unescapedString = new StringBuilder(); char[] hexChars; for (int i = 0; i < stringChars.length; i++) { if (stringChars[i] != '\\') { unescapedString.append(stringChars[i]); continue; } switch (stringChars[i + 1]) { case 'b': unescapedString.append('\b'); i++; break; case 'f': unescapedString.append('\f'); i++; break; case 'n': unescapedString.append('\n'); i++; break; case 'r': unescapedString.append('\r'); i++; break; case 't': unescapedString.append('\t'); i++; break; case '\'': unescapedString.append('\''); i++; break; case '"': unescapedString.append('"'); i++; break; case '\\': unescapedString.append('\\'); i++; break; case 'x': hexChars = new char[2]; hexChars[0] = stringChars[i + 2]; hexChars[1] = stringChars[i + 3]; unescapedString.append((char) Integer.parseInt(new String(hexChars), 16)); i += 3; break; case 'u': hexChars = new char[4]; hexChars[0] = stringChars[i + 2]; hexChars[1] = stringChars[i + 3]; hexChars[2] = stringChars[i + 4]; hexChars[3] = stringChars[i + 5]; unescapedString.append((char) Integer.parseInt(new String(hexChars), 16)); i += 5; break; default: throw new UnknownFormatConversionException("Escape sequence '\\" + stringChars[i + 1] + " in string '" + string + "' is not supported"); } } return unescapedString.toString().trim(); } }