/** * Copyright 2007-2008 University Of Southern California * * 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 edu.isi.pegasus.planner.code.generator.condor; import edu.isi.pegasus.planner.namespace.ENV; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; /** * This class implements the rules defined by HTCondor for quoting environment * values described here * http://research.cs.wisc.edu/htcondor/manual/v8.2/condor_submit.html * * The rules are described below * <pre> * The new syntax for specifying environment values: * * Put double quote marks around the entire argument string. This distinguishes the new syntax from the old. * The old syntax does not have double quote marks around it. * Any literal double quote marks within the string must be escaped by repeating the double quote mark. * 1) Each environment entry has the form <name>=<value> * 2) Use white space (space or tab characters) to separate environment entries. * 3) To put any white space in an environment entry, surround the space and as * much of the surrounding entry as desired with single quote marks. * 4) To insert a literal single quote mark, repeat the single quote mark anywhere * inside of a section surrounded by single quote marks. * Example: * * environment = "one=1 two=""2"" three='spacey ''quoted'' value'" * Produces the following environment entries: * * one=1 * two="2" * three=spacey 'quoted' value * </pre> * * * @author Karan Vahi * */ public class CondorEnvironmentEscape { /** * Defines the set of characters that require escaping. */ private char[] mEscapable = { '\'', '\"'}; /** * The characater to use if whitespace is detected */ private static final char WHITESPACE_ENCLOSING_CHARACTER = '\''; /** * Defines the default quoting and escaping rules, escaping the apostrophe, * double quote and backslash. The escape character is the backslash. * */ public CondorEnvironmentEscape() { } /** * Escapes all the profiles in the environment namespace per condor rules * for escaping environment variables * * <pre> * The new syntax for specifying environment values: * * Put double quote marks around the entire argument string. This distinguishes the new syntax from the old. * The old syntax does not have double quote marks around it. * Any literal double quote marks within the string must be escaped by repeating the double quote mark. * 1) Each environment entry has the form <name>=<value> * 2) Use white space (space or tab characters) to separate environment entries. * 3) To put any white space in an environment entry, surround the space and as * much of the surrounding entry as desired with single quote marks. * 4) To insert a literal single quote mark, repeat the single quote mark anywhere * inside of a section surrounded by single quote marks. * Example: * * environment = "one=1 two=""2"" three='spacey ''quoted'' value'" * Produces the following environment entries: * * one=1 * two="2" * three=spacey 'quoted' value * </pre> * * @param env * @return */ public String escape( ENV env ){ StringBuilder result = new StringBuilder(); //whole environment is enclosed in double quotes result.append( "\"" ); for( Iterator it = env.getProfileKeyIterator(); it.hasNext(); ){ String key = (String) it.next(); result.append( key ); result.append( "=" ); result.append( this.escape( (String)env.get(key))); result.append( " " ); } //end enclosing double quotes result.append( "\"" ); return result.toString(); } /** * Transforms a given string by escaping all characters inside the quotable * characters set with the escape character. The rules followed are described * below * <pre> * 1) To put any white space in an environment entry, surround the space and as * much of the surrounding entry as desired with single quote marks. * 2) To insert a literal single quote mark, repeat the single quote mark anywhere * inside of a section surrounded by single quote marks. * </pre> * * * @param s is the string to escape. * @return the quoted string */ public String escape(String s) { // sanity check if (s == null) { return null; } //first check for existence of whitespace boolean encloseInSingleQuote = false; StringBuilder result = new StringBuilder(s.length()); if( s.contains( " " ) ){ //we have to enclose the whole string with single quote marks encloseInSingleQuote = true; result.append( WHITESPACE_ENCLOSING_CHARACTER ); } for (int i = 0; i < s.length(); ++i) { char ch = s.charAt(i); if ( isEscapable( ch ) ) { //the escape characters are the ones //that are being escaped themselves! result.append( ch ); } result.append(ch); } if( encloseInSingleQuote ){ result.append( WHITESPACE_ENCLOSING_CHARACTER ); } return result.toString(); } /** * Test program. * * @param args are command-line arguments */ public static void main(String args[]) { CondorEnvironmentEscape me = new CondorEnvironmentEscape(); // defaults Map<String,String> m = new LinkedHashMap(); m.put( "one", "1" ); m.put( "two", "\"2\""); m.put( "three", "spacey 'quoted' value"); ENV env = new ENV( m ); //should print out "one=1 two=""2"" three='spacey ''quoted'' value' " String expected = "\"one=1 two=\"\"2\"\" three='spacey ''quoted'' value' \""; String result = me.escape(env); System.out.println( "escaping successful " + result.equals(expected) ); System.out.println( result ); } /** * Returns whether the character is escapable or not * * @return */ private boolean isEscapable(char ch) { return( ch == mEscapable[0] || ch == mEscapable[1] ); } }