PageRenderTime 22ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/asadmin-java/src/main/java/org/n0pe/asadmin/AsAdmin.java

http://github.com/Codeartisans/asadmin
Java | 375 lines | 301 code | 23 blank | 51 comment | 50 complexity | 68fbed96621a507679c0bba210139159 MD5 | raw file
Possible License(s): Apache-2.0
  1. /*
  2. * Copyright (c) 2010, Paul Merlin.
  3. * Copyright (c) 2010, Christophe Souvignier.
  4. * Copyright (c) 2010, Jean-Michel Tonneau.
  5. * Copyright (c) 2011, J. Francis.
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.n0pe.asadmin;
  18. import java.io.BufferedReader;
  19. import java.io.File;
  20. import java.io.IOException;
  21. import java.io.InputStream;
  22. import java.io.InputStreamReader;
  23. import java.util.ArrayList;
  24. import java.util.Arrays;
  25. import java.util.HashMap;
  26. import java.util.Iterator;
  27. import java.util.List;
  28. import java.util.Map;
  29. import org.apache.commons.lang.StringUtils;
  30. import org.apache.commons.lang.SystemUtils;
  31. import org.n0pe.asadmin.commands.Database;
  32. import org.n0pe.asadmin.commands.Deployment;
  33. import org.n0pe.asadmin.commands.Domain;
  34. /**
  35. * asadmin command execution facility built as a multipleton which discriminator is a configuration provider.
  36. *
  37. * TODO : allows AsAdminCommands to provide input lines for stdin, implements this command :
  38. * echo y | asadmin generate-diagnostic-report --outputfile report-dosadi.jar domainName
  39. *
  40. * TODO : handle asadmin invocation return codes with exceptions
  41. */
  42. public class AsAdmin
  43. {
  44. private static final String OUTPUT_PREFIX = "[ASADMIN] ";
  45. private static Map<IAsAdminConfig, AsAdmin> instances;
  46. public static final String HOST_OPT = "--host";
  47. public static final String PORT_OPT = "--port";
  48. public static final String SECURE_OPT = "--secure";
  49. public static final String USER_OPT = "--user";
  50. public static final String PASSWORDFILE_OPT = "--passwordfile";
  51. public static String ASADMIN_COMMAND_NAME;
  52. static
  53. {
  54. ASADMIN_COMMAND_NAME = SystemUtils.IS_OS_WINDOWS ? "asadmin.bat" : "asadmin";
  55. }
  56. private IAsAdminConfig config;
  57. /**
  58. * Get a asadmin instance configured with the given configuration provider.
  59. *
  60. * @param config
  61. * @return
  62. */
  63. public static AsAdmin getInstance( final IAsAdminConfig config )
  64. {
  65. if( instances == null )
  66. {
  67. instances = new HashMap<IAsAdminConfig, AsAdmin>( 1 );
  68. }
  69. AsAdmin instance = instances.get( config );
  70. if( instance == null )
  71. {
  72. instance = new AsAdmin( config );
  73. instances.put( config, instance );
  74. }
  75. return instance;
  76. }
  77. private AsAdmin( final IAsAdminConfig config )
  78. {
  79. this.config = config;
  80. }
  81. /**
  82. * Run the given list of AsAdmin command.
  83. *
  84. * @param cmdList AsAdmin commands to be run
  85. * @throws org.n0pe.asadmin.AsAdminException AsAdminException
  86. */
  87. public void run( final AsAdminCmdList cmdList )
  88. throws AsAdminException
  89. {
  90. final Iterator<IAsAdminCmd> it = cmdList.iterator();
  91. while( it.hasNext() )
  92. {
  93. run( it.next() );
  94. }
  95. }
  96. /**
  97. * Run the given AsAdmin command.
  98. *
  99. * @param cmd AsAdmin command to be run
  100. * @throws org.n0pe.asadmin.AsAdminException AsAdminException
  101. */
  102. public void run( final IAsAdminCmd cmd )
  103. throws AsAdminException
  104. {
  105. try
  106. {
  107. final File gfBinPath = new File( config.getGlassfishHome() + File.separator + "bin" );
  108. final String[] cmds = buildProcessParams( cmd, config );
  109. cmds[0] = gfBinPath + File.separator + cmds[0];
  110. int exitCode;
  111. final Process proc;
  112. String[] env = buildEnvironmentStrings( config.getEnvironmentVariables() );
  113. if( SystemUtils.IS_OS_WINDOWS )
  114. {
  115. // Windows
  116. final String command = "\"\"" + StringUtils.join( cmds, "\" \"" ) + "\"\"";
  117. final String[] windowsCommand;
  118. if( SystemUtils.IS_OS_WINDOWS_95 || SystemUtils.IS_OS_WINDOWS_98 || SystemUtils.IS_OS_WINDOWS_ME )
  119. {
  120. windowsCommand = new String[]
  121. {
  122. "command.com", "/C", command
  123. };
  124. }
  125. else
  126. {
  127. windowsCommand = new String[]
  128. {
  129. "cmd.exe", "/C", command
  130. };
  131. }
  132. outPrintln( "Will run the following command: " + StringUtils.join( windowsCommand, " " ) );
  133. if( env.length > 0 )
  134. {
  135. proc = Runtime.getRuntime().exec( windowsCommand, env );
  136. }
  137. else
  138. {
  139. proc = Runtime.getRuntime().exec( windowsCommand );
  140. }
  141. }
  142. else
  143. {
  144. // Non Windows
  145. outPrintln( "Will run the following command: " + StringUtils.join( cmds, " " ) );
  146. proc = Runtime.getRuntime().exec( cmds, env );
  147. }
  148. final ProcessStreamGobbler errorGobbler = new ProcessStreamGobbler( cmd,
  149. proc.getErrorStream(),
  150. ProcessStreamGobbler.ERROR );
  151. final ProcessStreamGobbler outputGobbler = new ProcessStreamGobbler( cmd,
  152. proc.getInputStream(),
  153. ProcessStreamGobbler.OUTPUT );
  154. errorGobbler.start();
  155. outputGobbler.start();
  156. exitCode = proc.waitFor();
  157. if( exitCode != 0 )
  158. {
  159. if( cmd.failOnNonZeroExit() )
  160. {
  161. throw new AsAdminException( "asadmin invocation failed and returned : " + String.valueOf( exitCode ) );
  162. }
  163. errPrintln( "Ignoring accpetable asadmin error" );
  164. }
  165. }
  166. catch( final InterruptedException ex )
  167. {
  168. throw new AsAdminException( "AsAdmin error occurred: " + ex.getMessage(), ex );
  169. }
  170. catch( final IOException ex )
  171. {
  172. throw new AsAdminException( "AsAdmin error occurred: " + ex.getMessage(), ex );
  173. }
  174. }
  175. public static String[] buildProcessParams( final IAsAdminCmd cmd, final IAsAdminConfig config )
  176. throws AsAdminException
  177. {
  178. final List<String> pbParams = new ArrayList<String>();
  179. pbParams.add( ASADMIN_COMMAND_NAME );
  180. if( !Deployment.UNDEPLOY.equals( cmd.getActionCommand() )
  181. && !Deployment.DEPLOY.equals( cmd.getActionCommand() )
  182. && !Deployment.REDEPLOY.equals( cmd.getActionCommand() )
  183. && !"add-resources".equals( cmd.getActionCommand() ) )
  184. {
  185. pbParams.add( cmd.getActionCommand() );
  186. }
  187. if( !StringUtils.isEmpty( config.getHost() )
  188. && !Domain.START.equals( cmd.getActionCommand() )
  189. && !Domain.STOP.equals( cmd.getActionCommand() )
  190. && !Database.STOP.equals( cmd.getActionCommand() )
  191. && !Database.START.equals( cmd.getActionCommand() ) )
  192. {
  193. pbParams.add( HOST_OPT );
  194. pbParams.add( config.getHost() );
  195. }
  196. if( !StringUtils.isEmpty( config.getPort() )
  197. && !Domain.START.equals( cmd.getActionCommand() )
  198. && !Domain.STOP.equals( cmd.getActionCommand() )
  199. && !Database.STOP.equals( cmd.getActionCommand() )
  200. && !Database.START.equals( cmd.getActionCommand() ) )
  201. {
  202. pbParams.add( PORT_OPT );
  203. pbParams.add( config.getPort() );
  204. }
  205. if( config.isSecure() )
  206. {
  207. pbParams.add( SECURE_OPT );
  208. }
  209. if( cmd.needCredentials() )
  210. {
  211. pbParams.add( USER_OPT );
  212. pbParams.add( config.getUser() );
  213. pbParams.add( PASSWORDFILE_OPT );
  214. pbParams.add( cmd.handlePasswordFile( config.getPasswordFile() ) );
  215. }
  216. if( Deployment.UNDEPLOY.equals( cmd.getActionCommand() )
  217. || Deployment.DEPLOY.equals( cmd.getActionCommand() )
  218. || Deployment.REDEPLOY.equals( cmd.getActionCommand() )
  219. || "add-resources".equals( cmd.getActionCommand() ) )
  220. {
  221. pbParams.add( cmd.getActionCommand() );
  222. }
  223. pbParams.addAll( Arrays.asList( cmd.getParameters() ) );
  224. return pbParams.toArray( new String[ pbParams.size() ] );
  225. }
  226. private static void outPrintln( final String message )
  227. {
  228. System.out.print( OUTPUT_PREFIX );
  229. System.out.println( message );
  230. }
  231. private static void errPrintln( final String message )
  232. {
  233. System.out.print( OUTPUT_PREFIX );
  234. System.out.println( message );
  235. }
  236. /**
  237. * Ensure variable names do not contains spaces and quote their values if needed.
  238. */
  239. /* package */ static String[] buildEnvironmentStrings( Map<String, String> envVariables )
  240. {
  241. if( envVariables == null || envVariables.isEmpty() )
  242. {
  243. return new String[]
  244. {
  245. };
  246. }
  247. String[] array = new String[ envVariables.size() ];
  248. int idx = 0;
  249. for( Map.Entry<String, String> eachEntry : envVariables.entrySet() )
  250. {
  251. String key = eachEntry.getKey().trim();
  252. if( !key.matches( "^\\S+$" ) )
  253. {
  254. throw new IllegalArgumentException( "Environment variable names cannot contain spaces: " + key );
  255. }
  256. String value = eachEntry.getValue();
  257. array[idx] = key + "=" + quoteArgument( value );
  258. idx++;
  259. }
  260. return array;
  261. }
  262. private static final String SINGLE_QUOTE = "\'";
  263. private static final String DOUBLE_QUOTE = "\"";
  264. private static String quoteArgument( final String argument )
  265. {
  266. String cleanedArgument = argument.trim();
  267. // strip the quotes from both ends
  268. while( cleanedArgument.startsWith( SINGLE_QUOTE ) || cleanedArgument.startsWith( DOUBLE_QUOTE ) )
  269. {
  270. cleanedArgument = cleanedArgument.substring( 1 );
  271. }
  272. while( cleanedArgument.endsWith( SINGLE_QUOTE ) || cleanedArgument.endsWith( DOUBLE_QUOTE ) )
  273. {
  274. cleanedArgument = cleanedArgument.substring( 0, cleanedArgument.length() - 1 );
  275. }
  276. final StringBuffer sb = new StringBuffer();
  277. if( cleanedArgument.indexOf( DOUBLE_QUOTE ) > -1 )
  278. {
  279. if( cleanedArgument.indexOf( SINGLE_QUOTE ) > -1 )
  280. {
  281. throw new IllegalArgumentException( "Can't handle single and double quotes in same argument" );
  282. }
  283. else
  284. {
  285. return sb.append( SINGLE_QUOTE ).append( cleanedArgument ).append( SINGLE_QUOTE ).toString();
  286. }
  287. }
  288. else if( cleanedArgument.indexOf( SINGLE_QUOTE ) > -1 || cleanedArgument.indexOf( " " ) > -1 )
  289. {
  290. return sb.append( DOUBLE_QUOTE ).append( cleanedArgument ).append( DOUBLE_QUOTE ).toString();
  291. }
  292. else
  293. {
  294. return cleanedArgument;
  295. }
  296. }
  297. /**
  298. * TODO : take a logger as constructor parameter and remove type
  299. */
  300. private static class ProcessStreamGobbler
  301. extends Thread
  302. {
  303. private static final int OUTPUT = 0;
  304. private static final int ERROR = 1;
  305. private AbstractAsAdminCmd cmd;
  306. private InputStream is;
  307. private int type = OUTPUT;
  308. private ProcessStreamGobbler( final IAsAdminCmd cmd, InputStream is, int type )
  309. {
  310. this.is = is;
  311. this.type = type;
  312. if( AbstractAsAdminCmd.class.isAssignableFrom( cmd.getClass() ) )
  313. {
  314. this.cmd = (AbstractAsAdminCmd) cmd;
  315. }
  316. }
  317. @Override
  318. @SuppressWarnings( "CallToThreadDumpStack" )
  319. public void run()
  320. {
  321. try
  322. {
  323. InputStreamReader isr = new InputStreamReader( is );
  324. BufferedReader br = new BufferedReader( isr );
  325. String line;
  326. while( ( line = br.readLine() ) != null )
  327. {
  328. switch( type )
  329. {
  330. case OUTPUT:
  331. if( cmd != null )
  332. {
  333. cmd.appendStandardOutputLine( line );
  334. }
  335. outPrintln( "[OUTPUT] " + line );
  336. break;
  337. case ERROR:
  338. if( cmd != null )
  339. {
  340. cmd.appendErrorOutputLine( line );
  341. }
  342. errPrintln( "[ERROR] " + line );
  343. }
  344. }
  345. }
  346. catch( IOException ioe )
  347. {
  348. ioe.printStackTrace();
  349. }
  350. }
  351. }
  352. }