AMQP-59: Merge admin project

- Try to get access to error message when connect fails
- Set default hostname to OS value
- Add -detached
This commit is contained in:
Dave Syer
2011-01-07 12:50:47 +00:00
parent 5a137fdb1d
commit fa81e49809
41 changed files with 634 additions and 1003 deletions

View File

@@ -17,6 +17,8 @@
package org.springframework.erlang.connection;
import org.springframework.util.Assert;
import com.ericsson.otp.erlang.OtpPeer;
import com.ericsson.otp.erlang.OtpSelf;
@@ -32,7 +34,8 @@ public class ConnectionParameters {
private OtpPeer otpPeer;
public ConnectionParameters(OtpSelf otpSelf, OtpPeer otpPeer) {
//TODO assert not null...
Assert.notNull(otpSelf, "OtpSelf must be non-null");
Assert.notNull(otpPeer, "OtpPeer must be non-null");
this.otpSelf = otpSelf;
this.otpPeer = otpPeer;
}

View File

@@ -1,17 +1,14 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* 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.
*
* 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.springframework.erlang.connection;
@@ -31,47 +28,42 @@ import com.ericsson.otp.erlang.OtpPeer;
import com.ericsson.otp.erlang.OtpSelf;
/**
* A simple implementation of {@link ConnectionFactory} that return a new connection
* for each invocation of the createConnection method.
*
* Note that use of this ConnectionFactory with ErlangTemplate has unstable behavior when
* invoked frequently and will be deprecated. See {@link SingleConnectionFactory} for an
* alternative implementation.
*
*
* Provides a more traditional API to creating a connection to a remote erlang node than
* the JInterface API.
*
* <p>The following is taken from the JInterface javadocs that describe the valid
* node names that can be used. These naming constraints apply to the string values
* you pass into the node names in SimpleConnectionFactory's constructor.
* <p>
* About nodenames: Erlang nodenames consist of two components, an alivename and
* a hostname separated by '@'. Additionally, there are two nodename formats:
* short and long. Short names are of the form "alive@hostname", while long
* names are of the form "alive@host.fully.qualified.domainname". Erlang has
* special requirements regarding the use of the short and long formats, in
* particular they cannot be mixed freely in a network of communicating nodes,
* however Jinterface makes no distinction. See the Erlang documentation for
* more information about nodenames.
* A simple implementation of {@link ConnectionFactory} that return a new connection for each invocation of the
* createConnection method.
* </p>
* <p>
* Note that use of this ConnectionFactory with ErlangTemplate has unstable behavior when invoked frequently and will be
* deprecated. See {@link SingleConnectionFactory} for an alternative implementation.
* </p>
* <p>
* Provides a more traditional API to creating a connection to a remote erlang node than the JInterface API.
* </p>
* <p>
* The following is taken from the JInterface javadocs that describe the valid node names that can be used. These naming
* constraints apply to the string values you pass into the node names in SimpleConnectionFactory's constructor.
* </p>
* <p>
* About nodenames: Erlang nodenames consist of two components, an alivename and a hostname separated by '@'.
* Additionally, there are two nodename formats: short and long. Short names are of the form "alive@hostname", while
* long names are of the form "alive@host.fully.qualified.domainname". Erlang has special requirements regarding the use
* of the short and long formats, in particular they cannot be mixed freely in a network of communicating nodes, however
* Jinterface makes no distinction. See the Erlang documentation for more information about nodenames.
* </p>
*
* <p>
* The constructors for the AbstractNode classes will create names exactly as
* you provide them as long as the name contains '@'. If the string you provide
* contains no '@', it will be treated as an alivename and the name of the local
* host will be appended, resulting in a shortname. Nodenames longer than 255
* characters will be truncated without warning.
* The constructors for the AbstractNode classes will create names exactly as you provide them as long as the name
* contains '@'. If the string you provide contains no '@', it will be treated as an alivename and the name of the local
* host will be appended, resulting in a shortname. Nodenames longer than 255 characters will be truncated without
* warning.
* </p>
*
* <p>
* Upon initialization, this class attempts to read the file .erlang.cookie in
* the user's home directory, and uses the trimmed first line of the file as the
* default cookie by those constructors lacking a cookie argument. If for any
* reason the file cannot be found or read, the default cookie will be set to
* the empty string (""). The location of a user's home directory is determined
* using the system property "user.home", which may not be automatically set on
* all platforms.
* Upon initialization, this class attempts to read the file .erlang.cookie in the user's home directory, and uses the
* trimmed first line of the file as the default cookie by those constructors lacking a cookie argument. If for any
* reason the file cannot be found or read, the default cookie will be set to the empty string (""). The location of a
* user's home directory is determined using the system property "user.home", which may not be automatically set on all
* platforms.
* </p>
* @author Mark Pollack
* @author Mark Fisher
@@ -79,9 +71,9 @@ import com.ericsson.otp.erlang.OtpSelf;
public class SimpleConnectionFactory implements ConnectionFactory, InitializingBean {
protected final Log logger = LogFactory.getLog(getClass());
private boolean uniqueSelfNodeName = true;
private String selfNodeName;
private String cookie;
@@ -92,7 +84,6 @@ public class SimpleConnectionFactory implements ConnectionFactory, InitializingB
private OtpPeer otpPeer;
public SimpleConnectionFactory(String selfNodeName, String cookie, String peerNodeName) {
this(selfNodeName, peerNodeName);
this.cookie = cookie;
@@ -103,17 +94,15 @@ public class SimpleConnectionFactory implements ConnectionFactory, InitializingB
this.peerNodeName = peerNodeName;
}
public Connection createConnection() throws UnknownHostException, OtpAuthException, IOException {
try {
return new DefaultConnection(otpSelf.connect(otpPeer));
}
catch (IOException ex) {
throw new OtpIOException("failed to connect from '" + this.selfNodeName
+ "' to peer node '" + this.peerNodeName + "'", ex);
} catch (IOException ex) {
throw new OtpIOException("failed to connect from '" + this.selfNodeName + "' to peer node '"
+ this.peerNodeName + "'", ex);
}
}
public boolean isUniqueSelfNodeName() {
return uniqueSelfNodeName;
}
@@ -123,8 +112,9 @@ public class SimpleConnectionFactory implements ConnectionFactory, InitializingB
}
public void afterPropertiesSet() {
Assert.isTrue(this.selfNodeName != null || this.peerNodeName != null,
"'selfNodeName' or 'peerNodeName' is required");
Assert.isTrue(this.selfNodeName != null && this.peerNodeName != null,
"'selfNodeName' and 'peerNodeName' are required");
String selfNodeNameToUse = this.selfNodeName;
if (isUniqueSelfNodeName()) {
selfNodeNameToUse = this.selfNodeName + "-" + UUID.randomUUID().toString();
@@ -133,16 +123,14 @@ public class SimpleConnectionFactory implements ConnectionFactory, InitializingB
try {
if (this.cookie == null) {
this.otpSelf = new OtpSelf(selfNodeNameToUse.trim());
}
else {
} else {
this.otpSelf = new OtpSelf(selfNodeNameToUse.trim(), this.cookie);
}
}
catch (IOException e) {
} catch (IOException e) {
throw new OtpIOException(e);
}
this.otpPeer = new OtpPeer(this.peerNodeName.trim());
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.erlang.core;
import java.io.Serializable;
/**
* Describes an Erlang application. Only three fields are supported as that is the level
* of information that rabbitmq returns when performing a status request.
@@ -25,7 +27,8 @@ package org.springframework.erlang.core;
* @author Mark Pollack
*
*/
public class Application {
@SuppressWarnings("serial")
public class Application implements Serializable {
private String description;

View File

@@ -124,9 +124,7 @@ public class ErlangTemplate extends ErlangAccessor implements ErlangOperations {
finally {
org.springframework.erlang.connection.ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
}
// TODO: physically close and reopen the connection if there is an exception
}

View File

@@ -19,13 +19,16 @@
*/
package org.springframework.erlang.core;
import java.io.Serializable;
/**
* Simple description class for an Erlang node.
*
* @author Mark Pollack
*
*/
public class Node {
@SuppressWarnings("serial")
public class Node implements Serializable {
private String name;

View File

@@ -1,17 +1,14 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* 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.
*
* 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.springframework.util.exec;
@@ -24,21 +21,22 @@ import java.io.StringReader;
import java.util.StringTokenizer;
import java.util.Vector;
/* Derived from ant exec task. All the 'backward compat with jdk1.1, 1.2'
removed. Since jdk1.3 supports working dir, no need for scripts.
All ant-specific code has been removed as well, this is a completely
independent component.
Costin
*/
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Runs an external program.
* Runs an external program. Derived from ant exec task. All the 'backward compat with jdk1.1, 1.2' removed. Since
* jdk1.3 supports working dir, no need for scripts. All ant-specific code has been removed as well, this is a
* completely independent component.
*
*
* @author thomas.haas@softwired-inc.com
* @author Costin Leau
*/
public class Execute {
private static Log log = LogFactory.getLog(Execute.class);
/** Invalid exit code. **/
public final static int INVALID = Integer.MAX_VALUE;
@@ -72,8 +70,7 @@ public class Execute {
// Just try to use what we got
}
BufferedReader in = new BufferedReader(new StringReader(
out.toString()));
BufferedReader in = new BufferedReader(new StringReader(out.toString()));
String var = null;
String line, lineSep = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
@@ -128,8 +125,7 @@ public class Execute {
}
/**
* Creates a new execute object using <code>PumpStreamHandler</code> for
* stream handling.
* Creates a new execute object using <code>PumpStreamHandler</code> for stream handling.
*/
public Execute() {
this(new PumpStreamHandler(), null);
@@ -138,9 +134,7 @@ public class Execute {
/**
* Creates a new execute object.
*
* @param streamHandler
* the stream handler used to handle the input and output streams
* of the subprocess.
* @param streamHandler the stream handler used to handle the input and output streams of the subprocess.
*/
public Execute(ExecuteStreamHandler streamHandler) {
this(streamHandler, null);
@@ -149,12 +143,8 @@ public class Execute {
/**
* Creates a new execute object.
*
* @param streamHandler
* the stream handler used to handle the input and output streams
* of the subprocess.
* @param watchdog
* a watchdog for the subprocess or <code>null</code> to to
* disable a timeout for the subprocess.
* @param streamHandler the stream handler used to handle the input and output streams of the subprocess.
* @param watchdog a watchdog for the subprocess or <code>null</code> to to disable a timeout for the subprocess.
*/
public Execute(ExecuteStreamHandler streamHandler, ExecuteWatchdog watchdog) {
this.streamHandler = streamHandler;
@@ -177,8 +167,7 @@ public class Execute {
/**
* Sets the commandline of the subprocess to launch.
*
* @param commandline
* the commandline of the subprocess to launch
* @param commandline the commandline of the subprocess to launch
*/
public void setCommandline(String[] commandline) {
cmdl = commandline;
@@ -187,8 +176,7 @@ public class Execute {
/**
* Set whether to propagate the default environment or not.
*
* @param newenv
* whether to propagate the process environment.
* @param newenv whether to propagate the process environment.
*/
public void setNewenvironment(boolean newenv) {
newEnvironment = newenv;
@@ -208,9 +196,8 @@ public class Execute {
/**
* Sets the environment variables for the subprocess to launch.
*
* @param env
* array of Strings, each element of which has an environment
* variable settings in format <em>key=value</em>
* @param env array of Strings, each element of which has an environment variable settings in format
* <em>key=value</em>
*/
public void setEnvironment(String[] env) {
this.env = env;
@@ -219,13 +206,10 @@ public class Execute {
/**
* Sets the working directory of the process to execute.
*
* <p>
* This is emulated using the antRun scripts unless the OS is Windows NT in
* which case a cmd.exe is spawned, or MRJ and setting user.dir works, or
* JDK 1.3 and there is official support in java.lang.Runtime.
* <p> This is emulated using the antRun scripts unless the OS is Windows NT in which case a cmd.exe is spawned, or
* MRJ and setting user.dir works, or JDK 1.3 and there is official support in java.lang.Runtime.
*
* @param wd
* the working directory of the process.
* @param wd the working directory of the process.
*/
public void setWorkingDirectory(File wd) {
workingDirectory = wd;
@@ -235,12 +219,10 @@ public class Execute {
* Runs a process defined by the command line and returns its exit status.
*
* @return the exit status of the subprocess or <code>INVALID</code>
* @throws Exception
* if launching of the subprocess failed
* @throws Exception if launching of the subprocess failed
*/
public int execute() throws Exception {
process = Runtime.getRuntime().exec(getCommandline(), getEnvironment(),
workingDirectory);
process = Runtime.getRuntime().exec(getCommandline(), getEnvironment(), workingDirectory);
try {
streamHandler.setProcessInputStream(process.getOutputStream());
streamHandler.setProcessOutputStream(process.getInputStream());
@@ -251,23 +233,29 @@ public class Execute {
}
streamHandler.start();
if (watchdog != null)
if (watchdog != null) {
watchdog.start(process, Thread.currentThread());
}
if (log.isTraceEnabled())
if (log.isTraceEnabled()) {
log.trace("Waiting process ");
}
waitFor(process);
process = null;
if (log.isTraceEnabled())
if (log.isTraceEnabled()) {
log.trace("End waiting, stop threads ");
if (watchdog != null)
}
if (watchdog != null) {
watchdog.stop();
if (log.isTraceEnabled())
}
if (log.isTraceEnabled()) {
log.trace("Watchdog stopped ");
}
streamHandler.stop();
if (log.isTraceEnabled())
if (log.isTraceEnabled()) {
log.trace("Stream handler stopped ");
}
if (watchdog != null) {
Exception ex = watchdog.getException();
if (ex != null)
@@ -302,6 +290,7 @@ public class Execute {
setExitValue(process.exitValue());
} catch (InterruptedException e) {
log.info("waitFor() interrupted ");
Thread.currentThread().interrupt();
}
}
@@ -312,8 +301,7 @@ public class Execute {
/**
* query the exit value of the process.
*
* @return the exit value, 1 if the process was killed, or Project.INVALID
* if no exit value has been received
* @return the exit value, 1 if the process was killed, or Project.INVALID if no exit value has been received
*/
public int getExitValue() {
return exitValue;
@@ -355,25 +343,19 @@ public class Execute {
return execute(envVars, v, baseDir);
}
public static int execute(Vector<String> envVars, Vector<String> cmd,
File baseDir) {
public static int execute(Vector<String> envVars, Vector<String> cmd, File baseDir) {
return execute(envVars, cmd, baseDir, 10000 /* default time to wait */);
}
/**
* Wrapper for common execution patterns
*
* @param envVars
* Environment variables to execute with (optional)
* @param cmd
* a vector of the commands to execute
* @param baseDir
* the base directory to run from (optional)
* @param timeToWait
* milliseconds to wait for completion
* @param envVars Environment variables to execute with (optional)
* @param cmd a vector of the commands to execute
* @param baseDir the base directory to run from (optional)
* @param timeToWait milliseconds to wait for completion
*/
public static int execute(Vector<String> envVars, Vector<String> cmd,
File baseDir, int timeToWait) {
public static int execute(Vector<String> envVars, Vector<String> cmd, File baseDir, int timeToWait) {
try {
// We can collect the out or provide in if needed
ExecuteWatchdog watchdog = new ExecuteWatchdog(timeToWait);
@@ -407,13 +389,9 @@ public class Execute {
log.debug("Exit value " + status);
return status;
} catch (Exception ex) {
// ex.printStackTrace();
System.err.println("An error has occurred in Execute.");
return -1;
}
}
private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
.getLog(Execute.class);
}

View File

@@ -103,7 +103,7 @@ public class ExecuteWatchdog implements Runnable {
/**
* Watches the process and terminates it, if it runs for to long.
* Watches the process and terminates it, if it runs for too long.
*/
public synchronized void run() {
try {
@@ -117,7 +117,7 @@ public class ExecuteWatchdog implements Runnable {
} catch (InterruptedException e) {}
}
// if we are here, either someone stopped the watchdog,
// If we are here, either someone stopped the watchdog,
// we are on timeout and the process must be killed, or
// we are on timeout and the process has already stopped.
try {
@@ -125,13 +125,11 @@ public class ExecuteWatchdog implements Runnable {
// before being here
process.exitValue();
} catch (IllegalThreadStateException e){
// the process is not terminated, if this is really
// The process is not terminated, if this is really
// a timeout and not a manual stop then kill it.
//System.out.println("ExecuteWatchdog: timeout");
if (watch){
killedProcess = true;
if( ! dontkill ) {
//System.out.println("ExecuteWatchdog: destroying process");
process.destroy();
}
if( execThread != null ) {
@@ -144,7 +142,6 @@ public class ExecuteWatchdog implements Runnable {
} finally {
cleanUp();
}
//System.out.println("ExecuteWatchdog: done");
}