3232
3333/**
3434 * This class implements the {@link DNSToSwitchMapping} interface using a
35- * script configured via the {@link CommonConfigurationKeys#NET_TOPOLOGY_SCRIPT_FILE_NAME_KEY}
35+ * script configured via the
36+ * {@link CommonConfigurationKeys#NET_TOPOLOGY_SCRIPT_FILE_NAME_KEY} option.
37+ * <p/>
38+ * It contains a static class <code>RawScriptBasedMapping</code> that performs
39+ * the work: reading the configuration parameters, executing any defined
40+ * script, handling errors and such like. The outer
41+ * class extends {@link CachedDNSToSwitchMapping} to cache the delegated
42+ * queries.
43+ * <p/>
44+ * This DNS mapper's {@link #isSingleSwitch()} predicate returns
45+ * true if and only if a script is defined.
3646 */
3747@ InterfaceAudience .Public
3848@ InterfaceStability .Evolving
39- public final class ScriptBasedMapping extends CachedDNSToSwitchMapping
40- implements Configurable
41- {
42- public ScriptBasedMapping () {
43- super (new RawScriptBasedMapping ());
44- }
49+ public final class ScriptBasedMapping extends CachedDNSToSwitchMapping {
4550
4651 /**
4752 * Minimum number of arguments: {@value}
@@ -65,6 +70,18 @@ public ScriptBasedMapping() {
6570 static final String SCRIPT_ARG_COUNT_KEY =
6671 CommonConfigurationKeys .NET_TOPOLOGY_SCRIPT_NUMBER_ARGS_KEY ;
6772
73+ /**
74+ * Create an instance with the default configuration.
75+ * </p>
76+ * Calling {@link #setConf(Configuration)} will trigger a
77+ * re-evaluation of the configuration settings and so be used to
78+ * set up the mapping script.
79+ *
80+ */
81+ public ScriptBasedMapping () {
82+ super (new RawScriptBasedMapping ());
83+ }
84+
6885 /**
6986 * Create an instance from the given configuration
7087 * @param conf configuration
@@ -74,44 +91,58 @@ public ScriptBasedMapping(Configuration conf) {
7491 setConf (conf );
7592 }
7693
94+ /**
95+ * Get the cached mapping and convert it to its real type
96+ * @return the inner raw script mapping.
97+ */
98+ private RawScriptBasedMapping getRawMapping () {
99+ return (RawScriptBasedMapping )rawMapping ;
100+ }
101+
77102 @ Override
78103 public Configuration getConf () {
79- return (( RawScriptBasedMapping ) rawMapping ).getConf ();
104+ return getRawMapping ( ).getConf ();
80105 }
81106
107+ /**
108+ * {@inheritDoc}
109+ * <p/>
110+ * This will get called in the superclass constructor, so a check is needed
111+ * to ensure that the raw mapping is defined before trying to relaying a null
112+ * configuration.
113+ * @param conf
114+ */
82115 @ Override
83116 public void setConf (Configuration conf ) {
84- ((RawScriptBasedMapping )rawMapping ).setConf (conf );
117+ super .setConf (conf );
118+ getRawMapping ().setConf (conf );
85119 }
86120
87121 /**
88122 * This is the uncached script mapping that is fed into the cache managed
89123 * by the superclass {@link CachedDNSToSwitchMapping}
90124 */
91125 private static final class RawScriptBasedMapping
92- implements DNSToSwitchMapping {
126+ extends AbstractDNSToSwitchMapping {
93127 private String scriptName ;
94- private Configuration conf ;
95128 private int maxArgs ; //max hostnames per call of the script
96- private static Log LOG =
129+ private static final Log LOG =
97130 LogFactory .getLog (ScriptBasedMapping .class );
98131
99132 /**
100- * Set the configuration and
101- * @param conf extract the configuration parameters of interest
133+ * Set the configuration and extract the configuration parameters of interest
134+ * @param conf the new configuration
102135 */
136+ @ Override
103137 public void setConf (Configuration conf ) {
104- this .scriptName = conf .get (SCRIPT_FILENAME_KEY );
105- this .maxArgs = conf .getInt (SCRIPT_ARG_COUNT_KEY , DEFAULT_ARG_COUNT );
106- this .conf = conf ;
107- }
108-
109- /**
110- * Get the configuration
111- * @return the configuration
112- */
113- public Configuration getConf () {
114- return conf ;
138+ super .setConf (conf );
139+ if (conf != null ) {
140+ scriptName = conf .get (SCRIPT_FILENAME_KEY );
141+ maxArgs = conf .getInt (SCRIPT_ARG_COUNT_KEY , DEFAULT_ARG_COUNT );
142+ } else {
143+ scriptName = null ;
144+ maxArgs = 0 ;
145+ }
115146 }
116147
117148 /**
@@ -122,42 +153,42 @@ public RawScriptBasedMapping() {}
122153
123154 @ Override
124155 public List <String > resolve (List <String > names ) {
125- List <String > m = new ArrayList <String >(names .size ());
126-
127- if (names .isEmpty ()) {
128- return m ;
129- }
156+ List <String > m = new ArrayList <String >(names .size ());
130157
131- if (scriptName == null ) {
132- for (int i = 0 ; i < names .size (); i ++) {
133- m .add (NetworkTopology .DEFAULT_RACK );
158+ if (names .isEmpty ()) {
159+ return m ;
134160 }
135- return m ;
136- }
137-
138- String output = runResolveCommand (names );
139- if (output != null ) {
140- StringTokenizer allSwitchInfo = new StringTokenizer (output );
141- while (allSwitchInfo .hasMoreTokens ()) {
142- String switchInfo = allSwitchInfo .nextToken ();
143- m .add (switchInfo );
161+
162+ if (scriptName == null ) {
163+ for (String name : names ) {
164+ m .add (NetworkTopology .DEFAULT_RACK );
165+ }
166+ return m ;
144167 }
145-
146- if (m .size () != names .size ()) {
147- // invalid number of entries returned by the script
148- LOG .error ("Script " + scriptName + " returned "
149- + Integer .toString (m .size ()) + " values when "
150- + Integer .toString (names .size ()) + " were expected." );
168+
169+ String output = runResolveCommand (names );
170+ if (output != null ) {
171+ StringTokenizer allSwitchInfo = new StringTokenizer (output );
172+ while (allSwitchInfo .hasMoreTokens ()) {
173+ String switchInfo = allSwitchInfo .nextToken ();
174+ m .add (switchInfo );
175+ }
176+
177+ if (m .size () != names .size ()) {
178+ // invalid number of entries returned by the script
179+ LOG .error ("Script " + scriptName + " returned "
180+ + Integer .toString (m .size ()) + " values when "
181+ + Integer .toString (names .size ()) + " were expected." );
182+ return null ;
183+ }
184+ } else {
185+ // an error occurred. return null to signify this.
186+ // (exn was already logged in runResolveCommand)
151187 return null ;
152188 }
153- } else {
154- // an error occurred. return null to signify this.
155- // (exn was already logged in runResolveCommand)
156- return null ;
189+
190+ return m ;
157191 }
158-
159- return m ;
160- }
161192
162193 /**
163194 * Build and execute the resolution command. The command is
@@ -195,10 +226,10 @@ private String runResolveCommand(List<String> args) {
195226 dir = new File (userDir );
196227 }
197228 ShellCommandExecutor s = new ShellCommandExecutor (
198- cmdList .toArray (new String [0 ]), dir );
229+ cmdList .toArray (new String [cmdList . size () ]), dir );
199230 try {
200231 s .execute ();
201- allOutput .append (s .getOutput () + " " );
232+ allOutput .append (s .getOutput ()). append ( " " );
202233 } catch (Exception e ) {
203234 LOG .warn ("Exception: " , e );
204235 return null ;
@@ -207,5 +238,15 @@ private String runResolveCommand(List<String> args) {
207238 }
208239 return allOutput .toString ();
209240 }
241+
242+ /**
243+ * Declare that the mapper is single-switched if a script was not named
244+ * in the configuration.
245+ * @return true iff there is no script
246+ */
247+ @ Override
248+ public boolean isSingleSwitch () {
249+ return scriptName == null ;
250+ }
210251 }
211252}
0 commit comments