AMQP-26 renamed 'spring-otp' to 'spring-erlang'

This commit is contained in:
Mark Fisher
2010-07-16 10:27:25 -04:00
parent c1f18ab83e
commit bade5f60f9
40 changed files with 9 additions and 9 deletions

View File

@@ -0,0 +1,48 @@
/*
* 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.
*/
package org.springframework.otp.erlang;
import com.ericsson.otp.erlang.OtpErlangTuple;
/**
* Exception thrown when an 'badrpc' is received from an Erlang RPC call.
* @author Mark Pollack
*
*/
public class ErlangBadRpcException extends OtpException {
private OtpErlangTuple reasonTuple;
public ErlangBadRpcException(String reason) {
super(reason);
}
public ErlangBadRpcException(OtpErlangTuple tuple) {
super(tuple.toString());
this.reasonTuple = tuple;
}
public OtpErlangTuple getReasonTuple() {
return reasonTuple;
}
}

View File

@@ -0,0 +1,43 @@
/*
* 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.
*/
package org.springframework.otp.erlang;
import com.ericsson.otp.erlang.OtpErlangTuple;
/**
* Exception thrown when an 'error' is received from an Erlang RPC call
* @author Mark Pollack
*
*/
public class ErlangErrorRpcException extends OtpException {
private OtpErlangTuple reasonTuple;
public ErlangErrorRpcException(String message) {
super(message);
}
public ErlangErrorRpcException(OtpErlangTuple tuple) {
super(tuple.toString());
this.reasonTuple = tuple;
}
public OtpErlangTuple getReasonTuple() {
return reasonTuple;
}
}

View File

@@ -0,0 +1,30 @@
/*
* 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.
*/
package org.springframework.otp.erlang;
/**
* Runtime exception mirroring the OTP OtpAuthException.
*
* @author Mark Pollack
*/
public class OtpAuthException extends OtpException {
public OtpAuthException(com.ericsson.otp.erlang.OtpAuthException cause) {
super(cause);
}
}

View File

@@ -0,0 +1,38 @@
/*
* 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.
*/
package org.springframework.otp.erlang;
/**
* Base RuntimeException for errors that occur when executing OTP operations.
*
* @author Mark Pollack
*/
public class OtpException extends RuntimeException {
public OtpException(String message) {
super(message);
}
public OtpException(Throwable cause) {
super(cause);
}
public OtpException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,38 @@
/*
* 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.
*/
package org.springframework.otp.erlang;
import java.io.IOException;
/**
* RuntimeException wrapper for an {@link IOException} which
* can be commonly thrown from OTP operations.
*
* @author Mark Pollack
* @author Mark Fisher
*/
public class OtpIOException extends OtpException {
public OtpIOException(IOException cause) {
super(cause);
}
public OtpIOException(String message, IOException cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,35 @@
/*
* 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.
*/
package org.springframework.otp.erlang;
/**
* A "catch-all" exception type within the OtpException hierarchy
* when no more specific cause is known.
*
* @author Mark Pollack
*/
public class UncategorizedOtpException extends OtpException {
public UncategorizedOtpException(Throwable cause) {
super(cause);
}
public UncategorizedOtpException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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.
*/
package org.springframework.otp.erlang.connection;
import java.io.IOException;
import java.net.UnknownHostException;
import com.ericsson.otp.erlang.OtpAuthException;
import com.ericsson.otp.erlang.OtpConnection;
/**
* An interface based ConnectionFactory for creating {@link OtpConnection}s.
*
* <p>NOTE: The Rabbit API contains a ConnectionFactory class (same name).
*
* @author Mark Pollack
*/
public interface ConnectionFactory {
OtpConnection createConnection() throws UnknownHostException, OtpAuthException, IOException;
}

View File

@@ -0,0 +1,48 @@
/*
* 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.
*/
package org.springframework.otp.erlang.connection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.ericsson.otp.erlang.OtpConnection;
/**
* @author Mark Pollack
*/
public class ConnectionFactoryUtils {
private static final Log logger = LogFactory.getLog(ConnectionFactoryUtils.class);
/**
* Release the given Connection by closing it.
*/
public static void releaseConnection(OtpConnection con, ConnectionFactory cf) {
if (con == null) {
return;
}
try {
con.close();
}
catch (Throwable ex) {
logger.debug("Could not close Otp Connection", ex);
}
}
}

View File

@@ -0,0 +1,48 @@
/*
* 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.
*/
package org.springframework.otp.erlang.connection;
import com.ericsson.otp.erlang.OtpPeer;
import com.ericsson.otp.erlang.OtpSelf;
/**
* Encapsulate properties to create a OtpConnection
* @author Mark Pollack
*
*/
public class ConnectionParameters {
private OtpSelf otpSelf;
private OtpPeer otpPeer;
public ConnectionParameters(OtpSelf otpSelf, OtpPeer otpPeer) {
//TODO assert not null...
this.otpSelf = otpSelf;
this.otpPeer = otpPeer;
}
public OtpSelf getOtpSelf() {
return otpSelf;
}
public OtpPeer getOtpPeer() {
return otpPeer;
}
}

View File

@@ -0,0 +1,87 @@
/*
* 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.
*/
package org.springframework.otp.erlang.connection;
import java.io.IOException;
import java.net.UnknownHostException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.otp.erlang.OtpIOException;
import org.springframework.util.Assert;
import com.ericsson.otp.erlang.OtpAuthException;
import com.ericsson.otp.erlang.OtpConnection;
import com.ericsson.otp.erlang.OtpPeer;
import com.ericsson.otp.erlang.OtpSelf;
/**
* @author Mark Pollack
* @author Mark Fisher
*/
public class SimpleConnectionFactory implements ConnectionFactory, InitializingBean {
private String selfNodeName;
private String cookie;
private String peerNodeName;
private OtpSelf otpSelf;
private OtpPeer otpPeer;
public SimpleConnectionFactory(String selfNodeName, String cookie, String peerNodeName) {
this.selfNodeName = selfNodeName;
this.cookie = cookie;
this.peerNodeName = peerNodeName;
}
public SimpleConnectionFactory(String selfNodeName, String peerNodeName) {
this.selfNodeName = selfNodeName;
this.peerNodeName = peerNodeName;
}
public OtpConnection createConnection() throws UnknownHostException, OtpAuthException, IOException {
try {
return otpSelf.connect(otpPeer);
}
catch (IOException ex) {
throw new OtpIOException("failed to connect from '" + this.selfNodeName
+ "' to peer node '" + this.peerNodeName + "'", ex);
}
}
public void afterPropertiesSet() {
Assert.isTrue(this.selfNodeName != null || this.peerNodeName != null,
"'selfNodeName' or 'peerNodeName' is required");
try {
if (this.cookie == null) {
this.otpSelf = new OtpSelf(this.selfNodeName);
}
else {
this.otpSelf = new OtpSelf(this.selfNodeName, this.cookie);
}
}
catch (IOException e) {
throw new OtpIOException(e);
}
this.otpPeer = new OtpPeer(this.peerNodeName);
}
}

View File

@@ -0,0 +1,64 @@
/*
* 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.
*/
package org.springframework.otp.erlang.core;
/**
* Describes an Erlang application. Only three fields are supported as that is the level
* of information that rabbitmq returns when performing a status request.
*
* See http://www.erlang.org/doc/man/app.html for full details
*
* @author Mark Pollack
*
*/
public class Application {
private String description;
private String id;
private String version;
public Application(String description, String id, String version) {
super();
this.description = description;
this.id = id;
this.version = version;
}
public String getDescription() {
return description;
}
public String getId() {
return id;
}
public String getVersion() {
return version;
}
@Override
public String toString() {
return "Application [description=" + description + ", id=" + id
+ ", version=" + version + "]";
}
}

View File

@@ -0,0 +1,33 @@
/*
* 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.
*/
package org.springframework.otp.erlang.core;
import com.ericsson.otp.erlang.OtpConnection;
/**
* Basic callback for use in ErlangTemplate
* @author Mark Pollack
*/
public interface ConnectionCallback<T> {
/**
* Execute any number of operations against the supplied OTP connection,
* possibly returning a result.
*/
T doInConnection(OtpConnection connection) throws Exception; //Not sure everything it throws
}

View File

@@ -0,0 +1,46 @@
/*
* 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.
*/
package org.springframework.otp.erlang.core;
import org.springframework.otp.erlang.OtpException;
import org.springframework.otp.erlang.support.converter.ErlangConverter;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangObject;
/**
* Operations to perform against OTP/Erlang
* @author Mark Pollack
*
*/
public interface ErlangOperations {
<T> T execute(ConnectionCallback<T> action) throws OtpException;
OtpErlangObject executeErlangRpc(String module, String function, OtpErlangList args) throws OtpException;
OtpErlangObject executeErlangRpc(String module, String function, OtpErlangObject... args) throws OtpException;
OtpErlangObject executeRpc(String module, String function, Object... args) throws OtpException;
Object executeAndConvertRpc(String module, String function, ErlangConverter converterToUse, Object... args) throws OtpException;
Object executeAndConvertRpc(String module, String function, Object... args) throws OtpException;
}

View File

@@ -0,0 +1,155 @@
/*
* 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.
*/
package org.springframework.otp.erlang.core;
import org.springframework.otp.erlang.ErlangErrorRpcException;
import org.springframework.otp.erlang.ErlangBadRpcException;
import org.springframework.otp.erlang.OtpException;
import org.springframework.otp.erlang.connection.ConnectionFactory;
import org.springframework.otp.erlang.support.ErlangAccessor;
import org.springframework.otp.erlang.support.ErlangUtils;
import org.springframework.otp.erlang.support.converter.ErlangConverter;
import org.springframework.otp.erlang.support.converter.SimpleErlangConverter;
import org.springframework.util.Assert;
import com.ericsson.otp.erlang.*;
/**
* @author Mark Pollack
*/
public class ErlangTemplate extends ErlangAccessor implements ErlangOperations {
private volatile ErlangConverter erlangConverter = new SimpleErlangConverter();
public ErlangTemplate(ConnectionFactory connectionFactory) {
setConnectionFactory(connectionFactory);
afterPropertiesSet();
}
public OtpErlangObject executeErlangRpc(final String module, final String function, final OtpErlangList args) {
return execute(new ConnectionCallback<OtpErlangObject>() {
public OtpErlangObject doInConnection(OtpConnection connection) throws Exception {
logger.debug("Sending RPC for module [" + module + "] function [" + function + "] args [" + args);
connection.sendRPC(module, function, args);
//TODO consider dedicated response object.
OtpErlangObject response = connection.receiveRPC();
logger.debug("Response received = " + response.toString());
handleResponseError(module, function, response);
return response;
}
});
}
public void handleResponseError(String module, String function, OtpErlangObject result) {
//{badrpc,{'EXIT',{undef,[{rabbit_access_control,list_users,[[]]},{rpc,'-handle_call/3-fun-0-',5}]}}}
if (result instanceof OtpErlangTuple) {
OtpErlangTuple msg = (OtpErlangTuple)result;
OtpErlangObject[] elements = msg.elements();
if (msg.elementAt(0) instanceof OtpErlangAtom)
{
OtpErlangAtom responseAtom = (OtpErlangAtom)msg.elementAt(0);
//TODO consider error handler strategy.
if (responseAtom.atomValue().equals("badrpc")) {
if (msg.elementAt(1) instanceof OtpErlangTuple) {
throw new ErlangBadRpcException( (OtpErlangTuple)msg.elementAt(1));
} else {
throw new ErlangBadRpcException( msg.elementAt(1).toString());
}
} else if (responseAtom.atomValue().equals("error")) {
if (msg.elementAt(1) instanceof OtpErlangTuple) {
throw new ErlangErrorRpcException( (OtpErlangTuple)msg.elementAt(1));
} else {
throw new ErlangErrorRpcException( msg.elementAt(1).toString());
}
}
}
}
}
public OtpErlangObject executeErlangRpc(String module, String function, OtpErlangObject... args) {
return executeRpc(module, function, new OtpErlangList(args));
}
public OtpErlangObject executeRpc(String module, String function, Object... args) {
return executeErlangRpc(module, function, (OtpErlangList) erlangConverter.toErlang(args));
}
public Object executeAndConvertRpc(String module, String function, ErlangConverter converterToUse, Object... args) {
return converterToUse.fromErlang(executeRpc(module, function, converterToUse.toErlang(args)));
}
public Object executeAndConvertRpc(String module, String function, Object... args) {
return erlangConverter.fromErlangRpc(module, function, executeErlangRpc(module, function, (OtpErlangList)erlangConverter.toErlang(args)));
}
public ErlangConverter getErlangConverter() {
return erlangConverter;
}
public void setErlangConverter(ErlangConverter erlangConverter) {
this.erlangConverter = erlangConverter;
}
public <T> T execute(ConnectionCallback<T> action) throws OtpException {
Assert.notNull(action, "Callback object must not be null");
OtpConnection con = null;
try {
con = createConnection();
return action.doInConnection(con);
}
catch (OtpException ex) {
throw ex;
}
catch (Exception ex) {
throw convertOtpAccessException(ex);
}
finally {
org.springframework.otp.erlang.connection.ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
}
}
/**
* Convert the specified checked exception to
* a Spring runtime exception equivalent.
* <p>The default implementation delegates to the
* {@link org.springframework.otp.erlang.support.ErlangUtils#convertOtpAccessException} method.
* @param ex the original checked {@link Exception} to convert
* @return the Spring runtime wrapping <code>ex</code>
* @see org.springframework.otp.erlang.support.ErlangUtils#convertOtpAccessException
*/
protected OtpException convertOtpAccessException(Exception ex) {
return ErlangUtils.convertOtpAccessException(ex);
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.
*/
/**
* Describes an Erlang node.
*/
package org.springframework.otp.erlang.core;
/**
* Simple description class for an Erlang node.
*
* @author Mark Pollack
*
*/
public class Node {
private String name;
public Node(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Node [name=" + name + "]";
}
}

View File

@@ -0,0 +1,64 @@
/*
* 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.
*/
package org.springframework.otp.erlang.support;
import java.io.IOException;
import java.net.UnknownHostException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.otp.erlang.OtpException;
import org.springframework.otp.erlang.connection.ConnectionFactory;
import com.ericsson.otp.erlang.OtpAuthException;
import com.ericsson.otp.erlang.OtpConnection;
/**
* @author Mark Pollack
*/
public abstract class ErlangAccessor implements InitializingBean {
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
private ConnectionFactory connectionFactory;
protected OtpConnection createConnection() throws UnknownHostException, OtpAuthException, IOException {
return getConnectionFactory().createConnection();
}
public void setConnectionFactory(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
public ConnectionFactory getConnectionFactory() {
return this.connectionFactory;
}
public void afterPropertiesSet() {
if (getConnectionFactory() == null) {
throw new IllegalArgumentException("Property 'connectionFactory' is required");
}
}
protected OtpException convertOtpAccessException(Exception ex) {
return ErlangUtils.convertOtpAccessException(ex);
}
}

View File

@@ -0,0 +1,53 @@
/*
* 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.
*/
package org.springframework.otp.erlang.support;
import java.io.IOException;
import org.springframework.otp.erlang.OtpException;
import org.springframework.otp.erlang.OtpIOException;
import org.springframework.otp.erlang.UncategorizedOtpException;
import org.springframework.util.Assert;
import com.ericsson.otp.erlang.OtpConnection;
/**
* @author Mark Pollack
*/
public class ErlangUtils {
/**
* Close the given Connection.
* @param con the Connection to close if necessary
* (if this is <code>null</code>, the call will be ignored)
*/
public static void releaseConnection(OtpConnection con) {
if (con == null) {
return;
}
con.close();
}
public static OtpException convertOtpAccessException(Exception ex) {
Assert.notNull(ex, "Exception must not be null");
if (ex instanceof IOException) {
return new OtpIOException((IOException) ex);
}
//fallback
return new UncategorizedOtpException(ex);
}
}

View File

@@ -0,0 +1,34 @@
/*
* 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.
*/
package org.springframework.otp.erlang.support.converter;
import org.springframework.otp.erlang.OtpException;
/**
* @author Mark Pollack
*/
public class ErlangConversionException extends OtpException {
public ErlangConversionException(String message, Throwable cause) {
super(message, cause);
}
public ErlangConversionException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.
*/
package org.springframework.otp.erlang.support.converter;
import com.ericsson.otp.erlang.OtpErlangObject;
/**
* Converter between Java and Erlang Types. Additional support for converting results from RPC calls.
*
* @author Mark Pollack
*/
public interface ErlangConverter {
/**
* Convert a Java object to a Erlang data type.
* @param object the object to convert
* @return the Erlang data type
* @throws ErlangConversionException in case of conversion failure
*/
OtpErlangObject toErlang(Object object) throws ErlangConversionException;
/**
* Convert from a Erlang data type to a Java object.
* @param erlangObject the Elang object to convert
* @return the converted Java object
* @throws ErlangConversionException in case of conversion failure
*/
Object fromErlang(OtpErlangObject erlangObject) throws ErlangConversionException;
Object fromErlangRpc(String module, String function, OtpErlangObject erlangObject) throws ErlangConversionException;
}

View File

@@ -0,0 +1,158 @@
/*
* 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.
*/
package org.springframework.otp.erlang.support.converter;
import java.util.ArrayList;
import com.ericsson.otp.erlang.OtpErlangAtom;
import com.ericsson.otp.erlang.OtpErlangBinary;
import com.ericsson.otp.erlang.OtpErlangBoolean;
import com.ericsson.otp.erlang.OtpErlangByte;
import com.ericsson.otp.erlang.OtpErlangChar;
import com.ericsson.otp.erlang.OtpErlangDouble;
import com.ericsson.otp.erlang.OtpErlangFloat;
import com.ericsson.otp.erlang.OtpErlangInt;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangLong;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangPid;
import com.ericsson.otp.erlang.OtpErlangRangeException;
import com.ericsson.otp.erlang.OtpErlangShort;
import com.ericsson.otp.erlang.OtpErlangString;
/**
* Converter that supports the basic types and arrays.
* @author Mark Pollack
*
*/
public class SimpleErlangConverter implements ErlangConverter {
public Object fromErlang(OtpErlangObject erlangObject)
throws ErlangConversionException {
//TODO support arrays.
return convertErlangToBasicType(erlangObject);
}
public Object fromErlangRpc(String module, String function,
OtpErlangObject erlangObject) throws ErlangConversionException {
return this.fromErlang(erlangObject);
}
public OtpErlangObject toErlang(Object obj)
throws ErlangConversionException {
if (obj instanceof OtpErlangObject) {
return (OtpErlangObject) obj;
}
if (obj instanceof Object[]) {
Object[] objectsToConvert = (Object[]) obj;
if (objectsToConvert.length != 0) {
ArrayList<OtpErlangObject> tempList = new ArrayList<OtpErlangObject>();
for (Object objectToConvert : objectsToConvert) {
OtpErlangObject erlangObject = convertBasicTypeToErlang(objectToConvert);
tempList.add(erlangObject);
}
OtpErlangObject ia[] = new OtpErlangObject[tempList.size()];
return new OtpErlangList(tempList.toArray(ia));
} else {
return new OtpErlangList();
}
} else {
return convertBasicTypeToErlang(obj);
}
}
protected OtpErlangObject convertBasicTypeToErlang(Object obj) {
if (obj instanceof byte[]) {
return new OtpErlangBinary((byte[]) obj);
} else if (obj instanceof Boolean) {
return new OtpErlangBoolean((Boolean) obj);
} else if (obj instanceof Byte) {
return new OtpErlangByte((Byte) obj);
} else if (obj instanceof Character) {
return new OtpErlangChar((Character) obj);
} else if (obj instanceof Double) {
return new OtpErlangDouble((Double) obj);
} else if (obj instanceof Float) {
return new OtpErlangFloat((Float) obj);
} else if (obj instanceof Integer) {
return new OtpErlangInt((Integer) obj);
} else if (obj instanceof Long) {
return new OtpErlangLong((Long) obj);
} else if (obj instanceof Short) {
return new OtpErlangShort((Short) obj);
} else if (obj instanceof String) {
return new OtpErlangString((String) obj);
} else {
throw new ErlangConversionException(
"Could not convert Java object of type [" + obj.getClass()
+ "] to an Erlang data type.");
}
}
protected Object convertErlangToBasicType(OtpErlangObject erlangObject) {
try {
if (erlangObject instanceof OtpErlangBinary) {
return ((OtpErlangBinary) erlangObject).binaryValue();
} else if (erlangObject instanceof OtpErlangAtom) {
return ((OtpErlangAtom) erlangObject).atomValue();
} else if (erlangObject instanceof OtpErlangBinary) {
return ((OtpErlangBinary) erlangObject).binaryValue();
} else if (erlangObject instanceof OtpErlangBoolean) {
return extractBoolean(erlangObject);
} else if (erlangObject instanceof OtpErlangByte) {
return ((OtpErlangByte) erlangObject).byteValue();
} else if (erlangObject instanceof OtpErlangChar) {
return ((OtpErlangChar) erlangObject).charValue();
} else if (erlangObject instanceof OtpErlangDouble) {
return ((OtpErlangDouble) erlangObject).doubleValue();
} else if (erlangObject instanceof OtpErlangFloat) {
return ((OtpErlangFloat) erlangObject).floatValue();
} else if (erlangObject instanceof OtpErlangInt) {
return ((OtpErlangInt) erlangObject).intValue();
} else if (erlangObject instanceof OtpErlangLong) {
return ((OtpErlangLong) erlangObject).longValue();
} else if (erlangObject instanceof OtpErlangShort) {
return ((OtpErlangShort) erlangObject).shortValue();
} else if (erlangObject instanceof OtpErlangString) {
return ((OtpErlangString) erlangObject).stringValue();
} else if (erlangObject instanceof OtpErlangPid) {
return ((OtpErlangPid) erlangObject).toString();
} else {
throw new ErlangConversionException(
"Could not convert Erlang object ["
+ erlangObject.getClass() + "] to Java type.");
}
} catch (OtpErlangRangeException e) {
throw new ErlangConversionException(
"Could not convert Erlang object ["
+ erlangObject.getClass() + "] to Java type.", e);
}
}
public static boolean extractBoolean(OtpErlangObject erlangObject) {
return ((OtpErlangBoolean) erlangObject).booleanValue();
}
public static String extractPid(OtpErlangObject value) {
return ((OtpErlangPid)value).toString();
}
public static long extractLong(OtpErlangObject value) {
return ((OtpErlangLong)value).longValue();
}
}

View File

@@ -0,0 +1,135 @@
/*
* 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.
*/
package org.springframework.util.exec;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
/**
* Class to execute processes in the background. These processes
* will not exit once the controlling Java process exits.
*/
public class Background {
/**
* Execute the command (and its args, ala Runtime.exec), sending the
* output && error streams to the void.
*/
public static void exec(String[] cmd)
throws IOException
{
File devNull;
if(Os.isFamily("unix"))
devNull = new File("/dev/null");
else if (Os.isFamily("windows"))
devNull = new File("NUL");
else
throw new IllegalStateException("Unhandled Java environment");
exec(cmd, devNull, false, devNull, false);
}
/**
* Execute a command (and its args, ala Runtime.exec)
*
* @param outFile File to send standard out from the process to
* @param appendOut If true, append the file with standard out,
* else truncate or create a new file
* @param errFile File to send standard err from the process to
* @param appendErr If true, append the file with standard error,
* else truncate or create a new file
*/
public static void exec(String[] cmd,
File outFile, boolean appendOut,
File errFile, boolean appendErr)
throws IOException
{
if(Os.isFamily("unix"))
execUnix(cmd, outFile, appendOut, errFile, appendErr);
else if (Os.isFamily("windows"))
execWin(cmd, outFile, appendOut, errFile, appendErr);
else
throw new IllegalStateException("Unhandled Java environment");
}
private static void execUnix(String[] cmd,
File outFile, boolean appendOut,
File errFile, boolean appendErr)
throws IOException
{
StringBuffer escaped;
String[] execCmd;
Runtime r;
escaped = new StringBuffer();
for(int i=0; i<cmd.length; i++){
escaped.append(Escape.escape(cmd[i]));
escaped.append(" ");
}
execCmd = new String[] {
"/bin/sh",
"-c",
escaped.toString() +
(appendOut == true ? ">>" : ">") +
Escape.escape(outFile.getAbsolutePath()) +
" 2" + (appendErr == true ? ">>" : " >") +
Escape.escape(errFile.getAbsolutePath()) +
" </dev/null &"
};
Process p = Runtime.getRuntime().exec(execCmd);
try {
p.waitFor();
} catch(Exception exc){
throw new IOException("Unable to properly background process: " +
exc.getMessage());
}
}
private static void execWin(String[] cmd,
File outFile, boolean appendOut,
File errFile, boolean appendErr)
throws IOException
{
String[] logargs;
String[] execCmd;
ArrayList tmpCmd = new ArrayList();
Runtime r;
tmpCmd.add("cmd");
tmpCmd.add("/c");
tmpCmd.add("start");
tmpCmd.add("/b");
tmpCmd.add("\"\"");
tmpCmd.add("/MIN");
for(int i=0; i<cmd.length; i++){
tmpCmd.add(cmd[i]);
}
tmpCmd.add((appendOut == true ? ">>" : ">") +
Escape.escape(outFile.getAbsolutePath()));
tmpCmd.add((outFile.equals(errFile) ? " 2&" : " 2") +
(appendErr == true ? ">>" : " >") +
Escape.escape(errFile.getAbsolutePath()));
Process p = Runtime.getRuntime().exec((String [])tmpCmd.toArray(cmd));
}
public static void main(String[] args) throws Exception {
Background.exec(new String[] {"javaq", "foo bar", "bar" },
new File("garfo"), true, new File("barfo"), true);
}
}

View File

@@ -0,0 +1,67 @@
/*
* 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.
*/
package org.springframework.util.exec;
public class Escape {
private static char[] enlargeArray(char[] in){
char[] res;
res = new char[in.length * 2];
System.arraycopy(in, 0, res, 0, in.length);
return res;
}
/**
* Escape a string by quoting the magical elements
* (such as whitespace, quotes, slashes, etc.)
*/
public static String escape(String in){
char[] inChars, outChars, resChars;
int numOut;
inChars = new char[in.length()];
outChars = new char[inChars.length];
in.getChars(0, inChars.length, inChars, 0);
numOut = 0;
for(int i=0; i<inChars.length; i++){
if(outChars.length - numOut < 5){
outChars = enlargeArray(outChars);
}
if(Character.isWhitespace(inChars[i]) ||
inChars[i] == '\\' ||
inChars[i] == '\'' ||
inChars[i] == '\"' ||
inChars[i] == '&' ||
inChars[i] == ';')
{
outChars[numOut++] = '\\';
outChars[numOut++] = inChars[i];
} else {
outChars[numOut++] = inChars[i];
}
}
return new String(outChars, 0, numOut);
}
public static void main(String[] args){
System.out.println(Escape.escape("foo bar"));
System.out.println(Escape.escape("\\\"foo' bar\""));
}
}

View File

@@ -0,0 +1,406 @@
/*
* 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.
*/
package org.springframework.util.exec;
import java.io.File;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.StringReader;
import java.io.ByteArrayOutputStream;
import java.util.*;
/* 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
*/
/**
* Runs an external program.
*
* @author thomas.haas@softwired-inc.com
*/
public class Execute {
/** Invalid exit code. **/
public final static int INVALID = Integer.MAX_VALUE;
private String[] cmdl = null;
private String[] env = null;
private int exitValue = INVALID;
private ExecuteStreamHandler streamHandler;
private ExecuteWatchdog watchdog;
private File workingDirectory = null;
private boolean newEnvironment = false;
private static Vector procEnvironment = null;
/**
* Find the list of environment variables for this process.
*/
public static synchronized Vector getProcEnvironment() {
if (procEnvironment != null) return procEnvironment;
procEnvironment = new Vector();
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Execute exe = new Execute(new PumpStreamHandler(out));
exe.setCommandline(getProcEnvCommand());
// Make sure we do not recurse forever
exe.setNewenvironment(true);
int retval = exe.execute();
if ( retval != 0 ) {
// Just try to use what we got
}
BufferedReader in =
new BufferedReader(new StringReader(out.toString()));
String var = null;
String line, lineSep = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
if (line.indexOf('=') == -1) {
// Chunk part of previous env var (UNIX env vars can
// contain embedded new lines).
if (var == null) {
var = lineSep + line;
}
else {
var += lineSep + line;
}
}
else {
// New env var...append the previous one if we have it.
if (var != null) {
procEnvironment.addElement(var);
}
var = line;
}
}
// Since we "look ahead" before adding, there's one last env var.
procEnvironment.addElement(var);
}
catch (Exception exc) {
exc.printStackTrace();
// Just try to see how much we got
}
return procEnvironment;
}
private static String[] getProcEnvCommand() {
if ( Os.isFamily("os/2") ) {
// OS/2 - use same mechanism as Windows 2000
// Not sure
String[] cmd = {"cmd", "/c", "set" };
return cmd;
}
else if ( Os.isFamily("windows") ) {
String osname =
System.getProperty("os.name").toLowerCase(Locale.US);
String[] cmd = {"cmd", "/c", "set" };
return cmd;
}
else if ( Os.isFamily("unix") ) {
// Generic UNIX
// Alternatively one could use: /bin/sh -c env
String[] cmd = {"/usr/bin/env"};
return cmd;
}
else if ( Os.isFamily("netware") ) {
String[] cmd = {"env"};
return cmd;
}
else {
// MAC OS 9 and previous
// TODO: I have no idea how to get it, someone must fix it
String[] cmd = null;
return cmd;
}
}
/**
* Creates a new execute object using <code>PumpStreamHandler</code> for
* stream handling.
*/
public Execute() {
this(new PumpStreamHandler(), null);
}
/**
* Creates a new execute object.
*
* @param streamHandler the stream handler used to handle the input and
* output streams of the subprocess.
*/
public Execute(ExecuteStreamHandler streamHandler) {
this(streamHandler, null);
}
/**
* 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.
*/
public Execute(ExecuteStreamHandler streamHandler, ExecuteWatchdog watchdog) {
this.streamHandler = streamHandler;
this.watchdog = watchdog;
}
/**
* Returns the commandline used to create a subprocess.
*
* @return the commandline used to create a subprocess
*/
public String[] getCommandline() {
return cmdl;
}
public String getCommandLineString() {
return array2string(getCommandline());
}
/**
* Sets the commandline of the subprocess to launch.
*
* @param commandline the commandline of the subprocess to launch
*/
public void setCommandline(String[] commandline) {
cmdl = commandline;
}
/**
* Set whether to propagate the default environment or not.
*
* @param newenv whether to propagate the process environment.
*/
public void setNewenvironment(boolean newenv) {
newEnvironment = newenv;
}
/**
* Returns the environment used to create a subprocess.
*
* @return the environment used to create a subprocess
*/
public String[] getEnvironment() {
if (env == null || newEnvironment) return env;
return patchEnvironment();
}
/**
* Sets the environment variables for the subprocess to launch.
*
* @param commandline 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;
}
/**
* 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.
*
* @param wd the working directory of the process.
*/
public void setWorkingDirectory(File wd) {
workingDirectory = wd;
}
// costin
boolean wait=true;
public void setWait( boolean b ) {
wait=b;
}
Process process;
/**
* Runs a process defined by the command line and returns its exit status.
*
* @return the exit status of the subprocess or <code>INVALID</code>
* @exception java.io.IOExcpetion The exception is thrown, if launching
* of the subprocess failed
*/
public int execute() throws Exception {
process =
Runtime.getRuntime().exec( getCommandline(), getEnvironment(),
workingDirectory );
try {
streamHandler.setProcessInputStream(process.getOutputStream());
streamHandler.setProcessOutputStream(process.getInputStream());
streamHandler.setProcessErrorStream(process.getErrorStream());
} catch (IOException e) {
process.destroy();
throw e;
}
streamHandler.start();
if (watchdog != null) watchdog.start(process,
Thread.currentThread());
if( log.isTraceEnabled() ) log.trace("Waiting process ");
waitFor(process);
if( log.isTraceEnabled() ) log.trace("End waiting, stop threads ");
if (watchdog != null) watchdog.stop();
if( log.isTraceEnabled() ) log.trace("Watchdog stopped ");
streamHandler.stop();
if( log.isTraceEnabled() ) log.trace("Stream handler stopped ");
if (watchdog != null) {
Exception ex=watchdog.getException();
if( ex!=null )
throw ex;
}
int exit= getExitValue();
if( log.isDebugEnabled() ) {
log.debug("Done exit=" + exit + " " + getCommandLineString());
}
return exit;
}
private String array2string( String sa[]) {
if( sa==null ) return "null";
StringBuffer sb=new StringBuffer();
for( int i=0; i<sa.length; i++ ) sb.append(sa[i]).append(" ");
return sb.toString();
}
protected void waitFor(Process process) {
try {
process.waitFor();
setExitValue(process.exitValue());
} catch (InterruptedException e) {
log.info("waitFor() interrupted ");
}
}
protected void setExitValue(int value) {
exitValue = value;
}
/**
* 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
*/
public int getExitValue() {
return exitValue;
}
/**
* Patch the current environment with the new values from the user.
* @return the patched environment
*/
private String[] patchEnvironment() {
Vector osEnv = (Vector) getProcEnvironment().clone();
for (int i = 0; i < env.length; i++) {
int pos = env[i].indexOf('=');
// Get key including "="
String key = env[i].substring(0, pos+1);
int size = osEnv.size();
for (int j = 0; j < size; j++) {
if (((String)osEnv.elementAt(j)).startsWith(key)) {
osEnv.removeElementAt(j);
break;
}
}
osEnv.addElement(env[i]);
}
String[] result = new String[osEnv.size()];
osEnv.copyInto(result);
return result;
}
public static int execute( Vector envVars, String cmd, File baseDir ) {
Vector v=new Vector();
StringTokenizer st=new StringTokenizer( cmd, " " );
while( st.hasMoreTokens() ) {
v.addElement( st.nextElement() );
}
return execute( envVars, v, baseDir );
}
public static int execute( Vector envVars, Vector 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
*/
public static int execute( Vector envVars, Vector cmd, File baseDir, int timeToWait) {
try {
// We can collect the out or provide in if needed
ExecuteWatchdog watchdog=new ExecuteWatchdog( timeToWait );
watchdog.setDontkill( true );
PumpStreamHandler out=new PumpStreamHandler();
Execute exec=new Execute(out,watchdog);
String cmdA[]=new String[ cmd.size() ];
cmd.toArray( cmdA );
if( log.isDebugEnabled() ) {
StringBuffer sb=new StringBuffer();
for(int i=0; i<cmdA.length; i++ ) {
sb.append(cmdA[i] + " " );
}
log.debug( "Exec: " + sb.toString());
}
exec.setCommandline( cmdA );
if( envVars!=null ) {
String env[]=new String[envVars.size()];
envVars.toArray( env );
exec.setEnvironment( env );
}
exec.setNewenvironment( false );
if( baseDir!=null)
exec.setWorkingDirectory( baseDir );
exec.execute();
int status=exec.getExitValue();
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

@@ -0,0 +1,62 @@
/*
* 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.
*/
package org.springframework.util.exec;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* Used by <code>Execute</code> to handle input and output stream of
* subprocesses.
*
* @author thomas.haas@softwired-inc.com
*/
public interface ExecuteStreamHandler {
/**
* Install a handler for the input stream of the subprocess.
*
* @param os output stream to write to the standard input stream of the
* subprocess
*/
void setProcessInputStream(OutputStream os) throws IOException;
/**
* Install a handler for the error stream of the subprocess.
*
* @param is input stream to read from the error stream from the subprocess
*/
void setProcessErrorStream(InputStream is) throws IOException;
/**
* Install a handler for the output stream of the subprocess.
*
* @param is input stream to read from the error stream from the subprocess
*/
void setProcessOutputStream(InputStream is) throws IOException;
/**
* Start handling of the streams.
*/
void start() throws IOException;
/**
* Stop handling of the streams - will not be restarted.
*/
void stop();
}

View File

@@ -0,0 +1,194 @@
/*
* 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.
*/
package org.springframework.util.exec;
/**
* Destroys a process running for too long.
* For example:
* <pre>
* ExecuteWatchdog watchdog = new ExecuteWatchdog(30000);
* Execute exec = new Execute(myloghandler, watchdog);
* exec.setCommandLine(mycmdline);
* int exitvalue = exec.execute();
* if (exitvalue != SUCCESS && watchdog.killedProcess()){
* // it was killed on purpose by the watchdog
* }
* </pre>
* @author thomas.haas@softwired-inc.com
* @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a>
* @see Execute
*/
public class ExecuteWatchdog implements Runnable {
/** the process to execute and watch for duration */
private Process process;
/** timeout duration. Once the process running time exceeds this it should be killed */
private int timeout;
/** say whether or not the watchog is currently monitoring a process */
private boolean watch = false;
/** exception that might be thrown during the process execution */
private Exception caught = null;
/** say whether or not the process was killed due to running overtime */
private boolean killedProcess = false;
Thread execThread;
private boolean dontkill=false;
/**
* Creates a new watchdog with a given timeout.
*
* @param timeout the timeout for the process in milliseconds. It must be greather than 0.
*/
public ExecuteWatchdog(int timeout) {
if (timeout < 1) {
throw new IllegalArgumentException("timeout lesser than 1.");
}
this.timeout = timeout;
}
public void setDontkill( boolean b ) {
dontkill=b;
}
/**
* Watches the given process and terminates it, if it runs for too long.
* All information from the previous run are reset.
* @param process the process to monitor. It cannot be <tt>null</tt>
* @throws IllegalStateException thrown if a process is still being monitored.
*/
public synchronized void start(Process process, Thread execThread) {
if (process == null) {
throw new NullPointerException("process is null.");
}
if (this.process != null) {
throw new IllegalStateException("Already running.");
}
this.caught = null;
this.killedProcess = false;
this.watch = true;
this.process = process;
final Thread thread = new Thread(this, "WATCHDOG");
this.execThread=execThread;
thread.setDaemon(true);
thread.start();
}
/**
* Stops the watcher. It will notify all threads possibly waiting on this object.
*/
public synchronized void stop() {
watch = false;
notifyAll();
}
/**
* Watches the process and terminates it, if it runs for to long.
*/
public synchronized void run() {
try {
// This isn't a Task, don't have a Project object to log.
// project.log("ExecuteWatchdog: timeout = "+timeout+" msec", Project.MSG_VERBOSE);
final long until = System.currentTimeMillis() + timeout;
long now;
while (watch && until > (now = System.currentTimeMillis())) {
try {
wait(until - now);
} catch (InterruptedException e) {}
}
// 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 {
// We must check if the process was not stopped
// before being here
process.exitValue();
} catch (IllegalThreadStateException e){
// 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 ) {
execThread.interrupt();
}
}
}
} catch(Exception e) {
caught = e;
} finally {
cleanUp();
}
//System.out.println("ExecuteWatchdog: done");
}
/**
* reset the monitor flag and the process.
*/
protected void cleanUp() {
watch = false;
process = null;
}
/**
* This method will rethrow the exception that was possibly caught during the
* run of the process. It will only remains valid once the process has been
* terminated either by 'error', timeout or manual intervention. Information
* will be discarded once a new process is ran.
* @throws BuildException a wrapped exception over the one that was silently
* swallowed and stored during the process run.
*/
// public void checkException() throws BuildException {
// if (caught != null) {
// throw new BuildException("Exception in ExecuteWatchdog.run: "
// + caught.getMessage(), caught);
// }
// }
public Exception getException() {
return caught;
}
/**
* Indicates whether or not the watchdog is still monitoring the process.
* @return <tt>true</tt> if the process is still running, otherwise <tt>false</tt>.
*/
public boolean isWatching(){
return watch;
}
/**
* Indicates whether the last process run was killed on timeout or not.
* @return <tt>true</tt> if the process was killed otherwise <tt>false</tt>.
*/
public boolean killedProcess(){
return killedProcess;
}
}

View File

@@ -0,0 +1,140 @@
/*
* 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.
*/
package org.springframework.util.exec;
import java.util.Locale;
/**
* Condition that tests the OS type.
*
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
* @author <a href="mailto:umagesh@apache.org">Magesh Umasankar</a>
*/
public class Os {
private static final String osName =
System.getProperty("os.name").toLowerCase(Locale.US);
private static final String osArch =
System.getProperty("os.arch").toLowerCase(Locale.US);
private static final String osVersion =
System.getProperty("os.version").toLowerCase(Locale.US);
private static final String pathSep = System.getProperty("path.separator");
/**
* Determines if the OS on which Ant is executing matches the
* given OS family.
*
* @param f The OS family type desired<br />
* Possible values:<br />
* <ul><li>dos</li>
* <li>mac</li>
* <li>netware</li>
* <li>os/2</li>
* <li>unix</li>
* <li>windows</li></ul>
* @since 1.5
*/
public static boolean isFamily(String family) {
return isOs(family, null, null, null);
}
/**
* Determines if the OS on which Ant is executing matches the
* given OS name.
*
* @since 1.7
*/
public static boolean isName(String name) {
return isOs(null, name, null, null);
}
/**
* Determines if the OS on which Ant is executing matches the
* given OS architecture.
*
* @since 1.7
*/
public static boolean isArch(String arch) {
return isOs(null, null, arch, null);
}
/**
* Determines if the OS on which Ant is executing matches the
* given OS version.
*
* @since 1.7
*/
public static boolean isVersion(String version) {
return isOs(null, null, null, version);
}
/**
* Determines if the OS on which Ant is executing matches the
* given OS family, name, architecture and version
*
* @param family The OS family
* @param name The OS name
* @param arch The OS architecture
* @param version The OS version
*
* @since 1.7
*/
public static boolean isOs(String family, String name, String arch,
String version) {
boolean retValue = false;
if (family != null || name != null || arch != null
|| version != null) {
boolean isFamily = true;
boolean isName = true;
boolean isArch = true;
boolean isVersion = true;
if (family != null) {
if (family.equals("windows")) {
isFamily = osName.indexOf("windows") > -1;
} else if (family.equals("os/2")) {
isFamily = osName.indexOf("os/2") > -1;
} else if (family.equals("netware")) {
isFamily = osName.indexOf("netware") > -1;
} else if (family.equals("dos")) {
isFamily = pathSep.equals(";") && !isFamily("netware");
} else if (family.equals("mac")) {
isFamily = osName.indexOf("mac") > -1;
} else if (family.equals("unix")) {
isFamily = pathSep.equals(":")
&& (!isFamily("mac") || osName.endsWith("x"));
} else {
throw new RuntimeException(
"Don\'t know how to detect os family \""
+ family + "\"");
}
}
if (name != null) {
isName = name.equals(osName);
}
if (arch != null) {
isArch = arch.equals(osArch);
}
if (version != null) {
isVersion = version.equals(osVersion);
}
retValue = isFamily && isName && isArch && isVersion;
}
return retValue;
}
}

View File

@@ -0,0 +1,125 @@
/*
* 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.
*/
package org.springframework.util.exec;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* Copies standard output and error of subprocesses to standard output and
* error of the parent process.
*
* TODO: standard input of the subprocess is not implemented.
*
* @author thomas.haas@softwired-inc.com
*/
public class PumpStreamHandler implements ExecuteStreamHandler {
private Thread inputThread;
private Thread errorThread;
private OutputStream out, err;
boolean running=false;
public PumpStreamHandler(OutputStream out, OutputStream err) {
this.out = out;
this.err = err;
}
public PumpStreamHandler(OutputStream outAndErr) {
this(outAndErr, outAndErr);
}
public PumpStreamHandler() {
this(System.out, System.err);
}
public void setProcessOutputStream(InputStream is) {
createProcessOutputPump(is, out);
}
public void setProcessErrorStream(InputStream is) {
createProcessErrorPump(is, err);
}
public void setProcessInputStream(OutputStream os) {
}
public void start() {
inputThread.start();
errorThread.start();
running=true;
}
public void stop() {
if( ! running ) return;
try {
//if( log.isDebugEnabled() ) log.debug("Joining it");
// inputThread.interrupt();
inputThread.join(1000);
//if( log.isDebugEnabled() ) log.debug("Joined" );
} catch(InterruptedException e) {}
try {
//if( log.isDebugEnabled() ) log.debug("Joining it");
// errorThread.interrupt();
errorThread.join(1000);
//if( log.isDebugEnabled() ) log.debug("Joined" );
} catch(InterruptedException e) {}
try {
err.flush();
} catch (IOException e) {}
try {
out.flush();
} catch (IOException e) {}
running=false;
}
protected OutputStream getErr() {
return err;
}
protected OutputStream getOut() {
return out;
}
protected void createProcessOutputPump(InputStream is, OutputStream os) {
inputThread = createPump(is, os);
}
protected void createProcessErrorPump(InputStream is, OutputStream os) {
errorThread = createPump(is, os);
}
/**
* Creates a stream pumper to copy the given input stream to the given output stream.
*/
protected Thread createPump(InputStream is, OutputStream os) {
final Thread result = new Thread(new StreamPumper(is, os));
result.setDaemon(true);
return result;
}
private static org.apache.commons.logging.Log log=
org.apache.commons.logging.LogFactory.getLog( PumpStreamHandler.class );
}

View File

@@ -0,0 +1,69 @@
/*
* 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.
*/
package org.springframework.util.exec;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Copies all data from an input stream to an output stream.
*
* @author thomas.haas@softwired-inc.com
*/
public class StreamPumper implements Runnable {
// TODO: make SIZE and SLEEP instance variables.
// TODO: add a status flag to note if an error occured in run.
private final static int SLEEP = 5;
private final static int SIZE = 128;
private InputStream is;
private OutputStream os;
/**
* Create a new stream pumper.
*
* @param is input stream to read data from
* @param os output stream to write data to.
*/
public StreamPumper(InputStream is, OutputStream os) {
this.is = is;
this.os = os;
}
/**
* Copies data from the input stream to the output stream.
*
* Terminates as soon as the input stream is closed or an error occurs.
*/
public void run() {
final byte[] buf = new byte[SIZE];
int length;
try {
while ((length = is.read(buf)) > 0) {
os.write(buf, 0, length);
try {
Thread.sleep(SLEEP);
} catch (InterruptedException e) {}
}
} catch(IOException e) {}
}
}