package org.codehaus.mojo.jboss;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.rmi.RMISecurityManager;
import java.util.Properties;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.maven.plugin.MojoExecutionException;
import org.jboss.security.SecurityAssociation;
import org.jboss.security.SimplePrincipal;
import org.jnp.interfaces.NamingContext;
/**
* Starts JBoss and waits until the server is started.
*
* @author <a href="mailto:jc7442@yahoo.fr">J-C</a>
* @author <a href="mailto:fuzail@fingerprintsoft.org">Fuzail Sarang</a>
* @goal start-and-wait
* @requiresProject false
* @since 1.4
*/
public class StartAndWaitMojo
extends StartMojo
{
/**
* One second in millis.
*/
public static final long ONE_SECOND = 1000;
/**
* Maximum number of retries to get JBoss JMX MBean connection.
*
* @parameter default-value="4" expression="${jboss.retry}"
*/
protected int retry;
/**
* Wait in ms before each retry of the JBoss JMX MBean connection.
*
* @parameter default-value="5000" expression="${jboss.retryWait}"
*/
protected int retryWait;
/**
* Time in ms to start the application server (once JMX MBean connection has been reached).
*
* @parameter default-value="20000" expression="${jboss.timeout}"
*/
protected int timeout;
/**
* The port for the naming service.
*
* @parameter default-value="1099" expression="${jboss.namingPort}"
*/
protected String namingPort;
/**
* The host JBoss is running on.
*
* @parameter default-value="localhost" expression="${jboss.hostname}"
*/
protected String hostName;
/**
* Main plugin execution.
*
* @throws MojoExecutionException
*/
public void execute()
throws MojoExecutionException
{
// Start JBoss
super.execute();
// Set up the security manager to allow remote code to execute.
try
{
File policyFile = File.createTempFile( "jboss-client", ".policy" );
policyFile.deleteOnExit();
JBossServerUtil.writeSecurityPolicy( policyFile );
// Get the canonical file which expands the shortened directory names in Windows
policyFile = policyFile.getCanonicalFile();
System.setProperty( "java.security.policy", policyFile.toURI().toString() );
System.setSecurityManager( new RMISecurityManager() );
}
catch ( IOException e )
{
getLog().info( "Unable to create security policy file for loading remote classes: " + e.getMessage(), e );
getLog().info( "Will try to load required classes from local classpath." );
}
catch ( SecurityException e )
{
getLog().info( "Unable to set security manager for loading remote classes: " + e.getMessage(), e );
getLog().info( "Will try to load required classes from local classpath." );
}
InitialContext ctx = getInitialContext();
// Try to get JBoss jmx MBean connection
MBeanServerConnection server = null;
NamingException ne = null;
for ( int i = 0; i < retry; ++i )
{
try
{
Thread.sleep( retryWait );
server = (MBeanServerConnection) ctx.lookup( "jmx/invoker/RMIAdaptor" );
break;
}
catch ( NamingException e )
{
ne = e;
getLog().info( "Waiting to retrieve JBoss JMX MBean connection... " );
}
catch ( InterruptedException e )
{
getLog().warn( "Thread interrupted while waiting for MBean connection: " + e.getMessage() );
e.printStackTrace();
}
}
if ( server == null )
{
throw new MojoExecutionException( "Unable to get JBoss JMX MBean connection: " + ne.getMessage(), ne );
}
getLog().info( "JBoss JMX MBean connection successful!" );
// Wait until server startup is complete
boolean started = false;
long startTime = System.currentTimeMillis();
while ( !started && System.currentTimeMillis() - startTime < timeout )
{
try
{
Thread.sleep( ONE_SECOND );
started = isStarted( server );
}
catch ( Exception e )
{
throw new MojoExecutionException( "Unable to wait: " + e.getMessage(), e );
}
}
if ( !started )
{
throw new MojoExecutionException( "JBoss AS is not stared before timeout has expired! " );
}
getLog().info( "JBoss AS started!" );
}
/**
* Check if the server has finished startup. Will throw one of several exceptions if the server connection fails.
*
* @param s
* @return
* @throws Exception
*/
protected boolean isStarted( MBeanServerConnection server )
throws Exception
{
ObjectName serverMBeanName = new ObjectName( "jboss.system:type=Server" );
return ( (Boolean) server.getAttribute( serverMBeanName, "Started" ) ).booleanValue();
}
/**
* Set up the context information for connecting the the jboss server.
*
* @return
* @throws MojoExecutionException
*/
protected InitialContext getInitialContext()
throws MojoExecutionException
{
Properties env = new Properties();
env.put( Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory" );
env.put( Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces" );
env.put( Context.PROVIDER_URL, hostName + ":" + namingPort );
env.put( NamingContext.JNP_DISABLE_DISCOVERY, "true" );
String username = getUsername();
if ( username != null )
{
SecurityAssociation.setPrincipal( new SimplePrincipal( username ) );
SecurityAssociation.setCredential( getPassword() );
}
try
{
return new InitialContext( env );
}
catch ( NamingException e )
{
throw new MojoExecutionException( "Unable to instantiate naming context: " + e.getMessage(), e );
}
}
}