/**
* @author ???
* 2011-08-27 Multi-instance support - marcolopes@netc.pt
*
*/
package com.google.code.magja.soap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import com.google.code.magja.magento.ResourcePath;
import com.google.code.magja.utils.PropertyLoader;
public class MagentoSoapClient implements SoapClient {
public static final String CONFIG_PROPERTIES_FILE = "magento-api";
private static final QName LOGIN_RETURN = new QName("loginReturn");
private static final QName LOGOUT_RETURN = new QName("endSessionReturn");
private static final QName CALL_RETURN = new QName("callReturn");
private SoapCallFactory callFactory;
private SoapReturnParser returnParser;
private SoapConfig config;
private Options connectOptions;
private String sessionId;
private ServiceClient sender;
// holds all the created instances by creation order, Multiton Pattern
private static final Map<SoapConfig, MagentoSoapClient> INSTANCES = new LinkedHashMap<SoapConfig, MagentoSoapClient>();
/**
* Returns the default instance, or a newly created one from the
* magento-api.properties file, if there is no default instance. The default
* instance is the first one created.
*
* @return the default instance or a newly created one
*/
public static MagentoSoapClient getInstance() {
return (INSTANCES.size() == 0) ? getInstance(null) : INSTANCES.values()
.iterator().next();
}
/**
* Returns the instance that was created with the specified configuration or
* create one if the instance does not exist.
*
* @return the already created instance or a new one
*/
public static MagentoSoapClient getInstance(SoapConfig soapConfig) {
// if has default instance and soapConfig is null
if(INSTANCES.size() > 0 && soapConfig == null)
return INSTANCES.values().iterator().next();
synchronized (INSTANCES) {
if (soapConfig == null)
soapConfig = new SoapConfig(
PropertyLoader.loadProperties(CONFIG_PROPERTIES_FILE));
MagentoSoapClient instance = INSTANCES.get(soapConfig);
if (instance == null) {
instance = new MagentoSoapClient(soapConfig);
INSTANCES.put(soapConfig, instance);
}
return instance;
}
}
/**
* Construct soap client using given configuration
*
* @param soapConfig
*/
private MagentoSoapClient(SoapConfig soapConfig) {
config = soapConfig;
callFactory = new SoapCallFactory();
returnParser = new SoapReturnParser();
try {
login();
} catch (AxisFault e) {
// do not swallow, rethrow as runtime
throw new RuntimeException(e);
}
}
/**
* @return the config
*/
public SoapConfig getConfig() {
return config;
}
/**
* Use to change the connection parameters to API (apiUser, apiKey,
* remoteHost)
*
* @param config
* the config to set
*/
@Deprecated
public void setConfig(SoapConfig config) throws AxisFault {
this.config = config;
login();
}
/*
* (non-Javadoc)
*
* @see
* com.google.code.magja.soap.SoapClient#call(com.google.code.magja.magento
* .ResourcePath, java.lang.Object)
*/
@Override
public Object call(ResourcePath path, Object args) throws AxisFault {
OMElement method = callFactory.createCall(sessionId, path.getPath(),
args);
OMElement result = sender.sendReceive(method);
return returnParser.parse(result.getFirstChildWithName(CALL_RETURN));
}
/*
* (non-Javadoc)
*
* @see com.google.code.magja.soap.SoapClient#multiCall(java.util.List,
* java.util.List)
*/
@Override
public Object multiCall(List<ResourcePath> path, List<Object> args)
throws AxisFault {
throw new UnsupportedOperationException("not implemented");
}
/**
* Connect to the service using the current config
*/
protected void login() throws AxisFault {
if (isLoggedIn())
logout();
connectOptions = new Options();
connectOptions.setTo(new EndpointReference(config.getRemoteHost()));
connectOptions.setTransportInProtocol(Constants.TRANSPORT_HTTP);
connectOptions.setTimeOutInMilliSeconds(60000);
// to use the same tcp connection for multiple calls
// workaround:
// http://amilachinthaka.blogspot.com/2009/05/improving-axis2-client-http-transport.html
MultiThreadedHttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager();
HttpClient httpClient = new HttpClient(httpConnectionManager);
connectOptions.setProperty(HTTPConstants.REUSE_HTTP_CLIENT,
Constants.VALUE_TRUE);
connectOptions
.setProperty(HTTPConstants.CACHED_HTTP_CLIENT, httpClient);
connectOptions.setProperty(HTTPConstants.HTTP_PROTOCOL_VERSION,
HTTPConstants.HEADER_PROTOCOL_10);
sender = new ServiceClient();
sender.setOptions(connectOptions);
OMElement loginMethod = callFactory.createLoginCall(
this.config.getApiUser(), this.config.getApiKey());
OMElement loginResult = sender.sendReceive(loginMethod);
sessionId = loginResult.getFirstChildWithName(LOGIN_RETURN).getText();
}
/**
* Logout from service, throws logout exception if failed
*
* @throws AxisFault
*/
protected void logout() throws AxisFault {
// first, we need to logout the previous session
OMElement logoutMethod = callFactory.createLogoutCall(sessionId);
OMElement logoutResult = sender.sendReceive(logoutMethod);
Boolean logoutSuccess = Boolean.parseBoolean(logoutResult
.getFirstChildWithName(LOGOUT_RETURN).getText());
if (!logoutSuccess) {
throw new RuntimeException("Error logging out");
}
sessionId = null;
}
/**
* Are we currently logged in?
*/
protected Boolean isLoggedIn() {
return sessionId != null;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#finalize()
*/
@Override
protected void finalize() throws Throwable {
// close the connection to magento api
// first, we need to logout the previous session
OMElement logoutMethod = callFactory.createLogoutCall(sessionId);
OMElement logoutResult = sender.sendReceive(logoutMethod);
Boolean logoutSuccess = Boolean.parseBoolean(logoutResult
.getFirstChildWithName(LOGOUT_RETURN).getText());
try {
sender.cleanupTransport();
} catch (Exception e) {
e.printStackTrace();
}
super.finalize();
}
}