/*****************************************************************************
* Copyright (c) 2006-2007, Cloudsmith Inc.
* The code, documentation and other materials contained herein have been
* licensed under the Eclipse Public License - v 1.0 by the copyright holder
* listed above, as the Initial Contributor under such license. The text of
* such license is available at www.eclipse.org.
*****************************************************************************/
package org.eclipse.buckminster.jnlp.distroprovider.cloudsmith;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.eclipse.buckminster.core.CorePlugin;
import org.eclipse.buckminster.core.TargetPlatform;
import org.eclipse.buckminster.core.helpers.CryptoUtils;
import org.eclipse.buckminster.core.metadata.model.BillOfMaterials;
import org.eclipse.buckminster.core.mspec.model.MaterializationSpec;
import org.eclipse.buckminster.core.parser.IParser;
import org.eclipse.buckminster.jnlp.Messages;
import org.eclipse.buckminster.jnlp.distroprovider.Distro;
import org.eclipse.buckminster.jnlp.distroprovider.DistroVariant;
import org.eclipse.buckminster.jnlp.distroprovider.IRemoteDistroProvider;
import org.eclipse.buckminster.jnlp.distroprovider.cloudsmith.IAccountService;
import org.eclipse.buckminster.jnlp.distroprovider.cloudsmith.LoginResponse;
import org.eclipse.osgi.util.NLS;
import org.jabsorb.client.Client;
import org.jabsorb.client.ErrorResponse;
import org.jabsorb.client.HTTPSession;
import org.jabsorb.client.TransportRegistry;
/**
* @author Karel Brezina
*
*/
public class DistroProvider implements IRemoteDistroProvider
{
abstract class MethodWrapper<T>
{
abstract public T process() throws Exception;
public T run() throws Exception
{
if(m_currentStatus == AuthenticationStatus.BEFORE_INIT && m_remoteAccountService == null)
{
throw new Exception(Messages.authenticator_is_not_initialized_initialize_method_needs_to_be_called);
}
try
{
return process();
}
catch(ErrorResponse e)
{
try
{
refresh();
return process();
}
catch(ErrorResponse e1)
{
throw new Exception(Messages.cannot_connect_to_the_remote_authentication_service, e1);
}
}
}
}
private enum AuthenticationStatus
{
BEFORE_INIT, AFTER_INIT, AFTER_LOGIN
}
private static final String ACCOUNTSERVICE_BRIDGE_URL_SUFFIX = "json-rpc-bridge/accountService"; //$NON-NLS-1$
private static final String ACCOUNTSERVICE_URL_SUFFIX = "json-rpc/accountService"; //$NON-NLS-1$
private static final String DISTROSERVICE_BRIDGE_URL_SUFFIX = "json-rpc-bridge/distroService"; //$NON-NLS-1$
private static final String DISTROSERVICE_URL_SUFFIX = "json-rpc/distroService"; //$NON-NLS-1$
private static final String ENCRYPT_ALGORITHM = "SHA-256"; //$NON-NLS-1$
private AuthenticationStatus m_currentStatus = AuthenticationStatus.BEFORE_INIT;
private String m_lastLoginUserName;
private String m_lastLoginPassword;
private String m_lastLoginKey;
private LoginResponse m_lastLoginResponse;
private String m_serviceURL;
private IAccountService m_remoteAccountService = null;
private IDistroService m_remoteDistroService = null;
private HttpClient m_httpClient;
public int checkFolderReadAccess(final String folderPath) throws Exception
{
MethodWrapper<Integer> method = new MethodWrapper<Integer>()
{
@Override
public Integer process() throws Exception
{
return Integer.valueOf(m_remoteAccountService.checkFolderReadAccess(folderPath));
}
};
return method.run().intValue();
}
public IRemoteDistroProvider createDuplicate(boolean login) throws Exception
{
DistroProvider authenticator = new DistroProvider();
authenticator.initialize(m_serviceURL);
if(m_currentStatus == AuthenticationStatus.AFTER_LOGIN && login)
{
if(m_lastLoginKey != null)
authenticator.login(m_lastLoginKey);
else
authenticator.login(m_lastLoginUserName, m_lastLoginPassword);
}
return authenticator;
}
public String getCurrenlyLoggedUserName()
{
return m_lastLoginResponse == null
? null
: m_lastLoginResponse.getUserName();
}
public Distro getDistro(final boolean draft, final Long cspecId, final Long distroId) throws Exception
{
MethodWrapper<Distro> method = new MethodWrapper<Distro>()
{
@Override
public Distro process() throws Exception
{
DistroContent distroContent = m_remoteDistroService.getDistro(draft, cspecId, distroId);
if(distroContent == null || distroContent.getBomContent() == null
|| distroContent.getMspecContent() == null)
return null;
IParser<BillOfMaterials> bomParser = CorePlugin.getDefault().getParserFactory()
.getBillOfMaterialsParser(true);
BillOfMaterials bom = bomParser
.parse(
"byte image", new ByteArrayInputStream(TransferUtils.decompress(distroContent.getBomContent()))); //$NON-NLS-1$
IParser<MaterializationSpec> mspecParser = CorePlugin.getDefault().getParserFactory()
.getMaterializationSpecParser(true);
MaterializationSpec mspec = mspecParser
.parse(
"byte image", new ByteArrayInputStream(TransferUtils.decompress(distroContent.getMspecContent()))); //$NON-NLS-1$
return new Distro(bom, mspec);
}
};
return method.run();
}
public List<DistroVariant> getDistroVariants(final boolean draft, final Long stackId) throws Exception
{
MethodWrapper<List<DistroVariant>> method = new MethodWrapper<List<DistroVariant>>()
{
@Override
public List<DistroVariant> process() throws Exception
{
Map<String, String> properties = new HashMap<String, String>();
properties.put(DistroVariant.TARGET_ARCH, TargetPlatform.getInstance().getArch());
properties.put(DistroVariant.TARGET_OS, TargetPlatform.getInstance().getOS());
properties.put(DistroVariant.TARGET_WS, TargetPlatform.getInstance().getWS());
properties.put(DistroVariant.TARGET_NL, TargetPlatform.getInstance().getNL());
return m_remoteDistroService.getDistroVariants(draft, stackId, properties);
}
};
return method.run();
}
public HttpClient getHttpClient()
{
return m_httpClient;
}
public String getLoginKey() throws Exception
{
MethodWrapper<String> method = new MethodWrapper<String>()
{
@Override
public String process() throws Exception
{
return m_remoteAccountService.getLoginKey();
}
};
return method.run();
}
public void initialize(String serviceURL) throws Exception
{
if(serviceURL == null)
{
throw new Exception(Messages.service_URL_is_missing);
}
m_serviceURL = serviceURL;
m_httpClient = new HttpClient();
HttpState httpState = new HttpState();
m_httpClient.setState(httpState);
GetMethod method = null;
// initialization of account service
try
{
method = new GetMethod(serviceURL + ACCOUNTSERVICE_BRIDGE_URL_SUFFIX);
int status = m_httpClient.executeMethod(method);
if(status != HttpStatus.SC_OK)
throw new IOException(NLS.bind(
Messages.setup_did_not_succeed_make_sure_the_AccountServiceServlet_servlet_is_running_on_0,
serviceURL));
}
finally
{
if(method != null)
method.releaseConnection();
}
TransportRegistry registry = new TransportRegistry();
HTTPSession.register(registry);
HTTPSession session = (HTTPSession)registry.createSession(serviceURL + ACCOUNTSERVICE_URL_SUFFIX);
// Pass the the session set up earlier
session.setState(httpState);
Client jsonClient = new Client(session);
m_remoteAccountService = (IAccountService)jsonClient.openProxy("accountService", IAccountService.class); //$NON-NLS-1$
m_currentStatus = AuthenticationStatus.AFTER_INIT;
// initialization of distro service
try
{
method = new GetMethod(serviceURL + DISTROSERVICE_BRIDGE_URL_SUFFIX);
int status = m_httpClient.executeMethod(method);
if(status != HttpStatus.SC_OK)
throw new IOException(NLS.bind(
Messages.setup_did_not_succeed_make_sure_the_DistroServiceServlet_servlet_is_running_on_0,
serviceURL));
}
finally
{
if(method != null)
method.releaseConnection();
}
session = (HTTPSession)registry.createSession(serviceURL + DISTROSERVICE_URL_SUFFIX);
// Pass the the session set up earlier
session.setState(httpState);
jsonClient = new Client(session);
m_remoteDistroService = (IDistroService)jsonClient.openProxy("distroService", IDistroService.class); //$NON-NLS-1$
}
public boolean isLoggedIn() throws Exception
{
MethodWrapper<Boolean> method = new MethodWrapper<Boolean>()
{
@Override
public Boolean process() throws Exception
{
return Boolean.valueOf(m_remoteAccountService.isLoggedIn());
}
};
return method.run().booleanValue();
}
public void keepAlive() throws Exception
{
MethodWrapper<Boolean> method = new MethodWrapper<Boolean>()
{
@Override
public Boolean process() throws Exception
{
m_remoteAccountService.keepAlive();
return Boolean.valueOf(true);
}
};
method.run();
}
public int login(final String loginKey) throws Exception
{
MethodWrapper<LoginResponse> method = new MethodWrapper<LoginResponse>()
{
@Override
public LoginResponse process() throws Exception
{
return m_remoteAccountService.login(loginKey);
}
};
m_lastLoginResponse = method.run();
int result = m_lastLoginResponse.getResponseId();
if(result == LOGIN_OK)
{
m_currentStatus = AuthenticationStatus.AFTER_LOGIN;
m_lastLoginUserName = null;
m_lastLoginPassword = null;
m_lastLoginKey = loginKey;
}
else
{
m_lastLoginResponse = null;
}
return result;
}
public int login(final String userName, final String password) throws Exception
{
MethodWrapper<LoginResponse> method = new MethodWrapper<LoginResponse>()
{
@Override
public LoginResponse process() throws Exception
{
return m_remoteAccountService.login(userName, CryptoUtils.encrypt(password, ENCRYPT_ALGORITHM));
}
};
m_lastLoginResponse = method.run();
int result = m_lastLoginResponse.getResponseId();
if(result == LOGIN_OK)
{
m_currentStatus = AuthenticationStatus.AFTER_LOGIN;
m_lastLoginUserName = userName;
m_lastLoginPassword = password;
m_lastLoginKey = null;
}
else
{
m_lastLoginResponse = null;
}
return result;
}
public int logout() throws Exception
{
int result;
try
{
result = logoutWithoutRefreshingConnection();
}
finally
{
initialize(m_serviceURL);
}
return result;
}
public int register(final String userName, final String password, final String email) throws Exception
{
MethodWrapper<Integer> method = new MethodWrapper<Integer>()
{
@Override
public Integer process() throws Exception
{
return Integer.valueOf(m_remoteAccountService.register(userName, CryptoUtils.encrypt(password,
ENCRYPT_ALGORITHM), email));
}
};
return method.run().intValue();
}
public void releaseConnection() throws Exception
{
logoutWithoutRefreshingConnection();
}
public int relogin(final String loginKey) throws Exception
{
if(isLoggedIn())
{
if(loginKey != null && loginKey.equals(m_lastLoginKey))
return IRemoteDistroProvider.LOGIN_OK;
logout();
}
return login(loginKey);
}
public int relogin(final String userName, final String password) throws Exception
{
if(isLoggedIn())
{
if(userName != null && userName.equals(m_lastLoginUserName) && password != null
&& password.equals(m_lastLoginPassword))
return IRemoteDistroProvider.LOGIN_OK;
logout();
}
return login(userName, password);
}
private int logoutWithoutRefreshingConnection() throws Exception
{
MethodWrapper<Integer> method = new MethodWrapper<Integer>()
{
@Override
public Integer process() throws Exception
{
return Integer.valueOf(m_remoteAccountService.logoutSession());
}
};
int result;
try
{
result = method.run().intValue();
}
finally
{
m_currentStatus = AuthenticationStatus.BEFORE_INIT;
m_remoteAccountService = null;
}
return result;
}
// refreshes connection after session timeout
private void refresh() throws Exception
{
if(m_currentStatus == AuthenticationStatus.BEFORE_INIT)
return;
initialize(m_serviceURL);
if(m_currentStatus == AuthenticationStatus.AFTER_INIT)
return;
if(m_lastLoginKey != null)
login(m_lastLoginKey);
else
login(m_lastLoginUserName, m_lastLoginPassword);
}
}