package org.ovirt.engine.core.bll;
import java.io.File;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.ejb.EJB;
import javax.ejb.Local;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.interceptor.ExcludeClassInterceptors;
import javax.interceptor.Interceptors;
import org.apache.commons.collections.KeyValue;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.jboss.ejb3.annotation.Management;
import org.jboss.ejb3.annotation.Service;
import org.ovirt.engine.core.bll.context.CompensationContext;
import org.ovirt.engine.core.bll.interfaces.BackendInternal;
import org.ovirt.engine.core.bll.session.SessionDataContainer;
import org.ovirt.engine.core.common.action.LoginUserParameters;
import org.ovirt.engine.core.common.action.LogoutUserParameters;
import org.ovirt.engine.core.common.action.VdcActionParametersBase;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.action.VdcReturnValueBase;
import org.ovirt.engine.core.common.businessentities.VDSStatus;
import org.ovirt.engine.core.common.businessentities.tags;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.interfaces.BackendLocal;
import org.ovirt.engine.core.common.interfaces.ErrorTranslator;
import org.ovirt.engine.core.common.interfaces.ITagsHandler;
import org.ovirt.engine.core.common.interfaces.VDSBrokerFrontend;
import org.ovirt.engine.core.common.queries.AsyncQueryResults;
import org.ovirt.engine.core.common.queries.ConfigurationValues;
import org.ovirt.engine.core.common.queries.GetConfigurationValueParameters;
import org.ovirt.engine.core.common.queries.VdcQueryParametersBase;
import org.ovirt.engine.core.common.queries.VdcQueryReturnValue;
import org.ovirt.engine.core.common.queries.VdcQueryType;
import org.ovirt.engine.core.compat.DateTime;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.LogCompat;
import org.ovirt.engine.core.compat.LogFactoryCompat;
import org.ovirt.engine.core.compat.NotImplementedException;
import org.ovirt.engine.core.compat.StringHelper;
import org.ovirt.engine.core.dal.VdcBllMessages;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
import org.ovirt.engine.core.dal.dbbroker.generic.DBConfigUtils;
import org.ovirt.engine.core.searchbackend.BaseConditionFieldAutoCompleter;
import org.ovirt.engine.core.utils.ErrorTranslatorImpl;
import org.ovirt.engine.core.utils.ThreadLocalParamsContainer;
import org.ovirt.engine.core.utils.ThreadLocalSessionCleanerInterceptor;
import org.ovirt.engine.core.utils.ejb.BeanProxyType;
import org.ovirt.engine.core.utils.ejb.BeanType;
import org.ovirt.engine.core.utils.ejb.EjbUtils;
import org.ovirt.engine.core.utils.timer.SchedulerUtil;
import org.ovirt.engine.core.utils.timer.SchedulerUtilQuartzImpl;
@Local({ BackendLocal.class, BackendInternal.class })
@Interceptors({ ThreadLocalSessionCleanerInterceptor.class })
@Service
@Management(BackendLocal.class)
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public class Backend implements BackendInternal, BackendRemote {
@SuppressWarnings("unused")
@EJB
private SchedulerUtil scheduler;
private ITagsHandler mTagsHandler;
private ErrorTranslator errorsTranslator;
private ErrorTranslator _vdsErrorsTranslator;
private DateTime _startedAt;
private static boolean firstInitialization = true;
public static BackendInternal getInstance() {
return EjbUtils.findBean(BeanType.BACKEND, BeanProxyType.LOCAL);
}
private void InitHandlers() {
mTagsHandler = HandlersFactory.createTagsHandler();
BaseConditionFieldAutoCompleter.TagsHandler = mTagsHandler;
VmHandler.Init();
VdsHandler.Init();
VmTemplateHandler.Init();
}
private VDSBrokerFrontend _resourceManger;
@ExcludeClassInterceptors
public VDSBrokerFrontend getResourceManager() {
return _resourceManger;
}
/**
* This method is called upon the bean creation as part
* of the management Service bean lifecycle.
*/
public void create() {
checkDBConnectivity();
Initialize();
}
private void checkDBConnectivity() {
boolean dbUp = false;
long expectedTimeout =
System.currentTimeMillis()
+ DbFacade.getInstance().getOnStartConnectionTimeout();
long waitBetweenInterval = DbFacade.getInstance().getConnectionCheckInterval();
while (!dbUp && System.currentTimeMillis() < expectedTimeout) {
try {
dbUp = DbFacade.getInstance().CheckDBConnection();
try {
Thread.sleep(waitBetweenInterval);
} catch (InterruptedException e) {
log.warn("Failed to wait between connection polling attempts. " +
"Original exception is: " + ExceptionUtils.getMessage(e));
}
} catch (RuntimeException ex) {
log.error("Error in getting DB connection. The database is inaccessible. " +
"Original exception is: " + ExceptionUtils.getMessage(ex));
}
}
if (!dbUp) {
throw new IllegalStateException("Could not obtain connection to the database." +
" Please make sure that DB is up and accepting connections, and " +
"restart the application.");
}
}
public DateTime getStartedAt() {
return _startedAt;
}
/**
* Initializes internal data
*
* <exception>VdcBLL.VdcBLLException
*/
public void Initialize() {
log.infoFormat("Start time: {0}", new java.util.Date());
// When getting a proxy to this bean using JBoss embedded, the initialize method is called for each method
// invocation on the proxy, as it is called by setup method which is @PostConstruct - the initialized flag
// makes sure that initialization occurs only once per class (which is ok, as this is a @Service)
if (firstInitialization) {
// In case of a server termination that had uncompleted compensation-aware related commands
// we have to get all those commands and call compensate on each
compensate();
firstInitialization = false;
}
// initialize configuration utils to use DB
Config.setConfigUtils(new DBConfigUtils());
_resourceManger = new VDSBrokerFrontendImpl();
log.infoFormat("VDSBrokerFrontend: {0}", new java.util.Date());
CpuFlagsManagerHandler.InitDictionaries();
log.infoFormat("CpuFlagsManager: {0}", new java.util.Date());
// ResourceManager res = ResourceManager.Instance;
// Initialize the AuditLogCleanupManager
AuditLogCleanupManager.getInstance();
log.infoFormat("AuditLogCleanupManager: {0}", new java.util.Date());
TagsDirector.getInstance();
log.infoFormat("TagsDirector: {0}", new java.util.Date());
ImagesSyncronizer.getInstance();
log.infoFormat("ImagesSyncronizer: {0}", new java.util.Date());
IsoDomainListSyncronizer.getInstance();
log.infoFormat("IsoDomainListSyncronizer: {0}", new java.util.Date());
InitHandlers();
log.infoFormat("InitHandlers: {0}", new java.util.Date());
final String AppErrorsFileName = "bundles/AppErrors.properties";
final String VdsErrorsFileName = "bundles/VdsmErrors.properties";
errorsTranslator = new ErrorTranslatorImpl(AppErrorsFileName, VdsErrorsFileName);
log.infoFormat("ErrorTranslator: {0}", new java.util.Date());
_vdsErrorsTranslator = new ErrorTranslatorImpl(VdsErrorsFileName);
log.infoFormat("VdsErrorTranslator: {0}", new java.util.Date());
Integer sessionTimoutInterval = Config.<Integer> GetValue(ConfigValues.UserSessionTimeOutInterval);
// negative value means session should never expire, therefore no need to clean sessions.
if (sessionTimoutInterval > 0) {
SchedulerUtilQuartzImpl.getInstance().scheduleAFixedDelayJob(SessionDataContainer.getInstance(),
"cleanExpiredUsersSessions", new Class[] {}, new Object[] {},
sessionTimoutInterval,
sessionTimoutInterval, TimeUnit.MINUTES);
}
// Set start-up time
_startedAt = DateTime.getNow();
try{
File fLock = new File(Config.<String> GetValue(ConfigValues.SignLockFile));
if (fLock.exists()) {
if (! fLock.delete()) {
log.error("Cleanup lockfile failed to delete the locking file.");
}
}
}
catch (SecurityException se) {
log.error("Cleanup lockfile failed!", se);
}
}
/**
* Handles compensation in case of uncompleted compensation-aware commands resulted from server failure.
*/
private void compensate() {
// get all command snapshot entries
List<KeyValue> commandSnapshots =
DbFacade.getInstance().getBusinessEntitySnapshotDAO().getAllCommands();
for (KeyValue commandSnapshot : commandSnapshots) {
// create an instance of the related command by its class name and command id
CommandBase<?> cmd =
CommandsFactory.CreateCommand(commandSnapshot.getValue().toString(),
(Guid) commandSnapshot.getKey());
if (cmd != null) {
cmd.compensate();
log.infoFormat("Running compensation on startup for Command : {0} , Command Id : {1}",
commandSnapshot.getValue(), commandSnapshot.getKey());
} else {
log.errorFormat("Failed to run compensation on startup for Command {0} , Command Id : {1}",
commandSnapshot.getValue(), commandSnapshot.getKey());
}
}
}
@ExcludeClassInterceptors
public VdcReturnValueBase runInternalAction(VdcActionType actionType, VdcActionParametersBase parameters) {
return runActionImpl(actionType, parameters, true, null);
}
public VdcReturnValueBase RunAction(VdcActionType actionType, VdcActionParametersBase parameters) {
return runActionImpl(actionType, parameters, false, null);
}
private VdcReturnValueBase runActionImpl(VdcActionType actionType, VdcActionParametersBase parameters,
boolean runAsInternal, CompensationContext context) {
switch (actionType) {
case AutoLogin:
VdcReturnValueBase returnValue = new VdcReturnValueBase();
returnValue.setCanDoAction(false);
returnValue.getCanDoActionMessages().add(VdcBllMessages.USER_NOT_AUTHORIZED_TO_PERFORM_ACTION.toString());
return returnValue;
default: {
CommandBase command = CommandsFactory.CreateCommand(actionType, parameters);
command.setInternalExecution(runAsInternal);
if (context != null) {
command.setCompensationContext(context);
}
return command.ExecuteAction();
}
}
}
@Override
public VdcReturnValueBase endAction(VdcActionType actionType,
VdcActionParametersBase parameters,
CompensationContext compensationContext) {
CommandBase<?> command = CommandsFactory.CreateCommand(actionType, parameters);
if (compensationContext != null) {
command.setCompensationContext(compensationContext);
}
return command.EndAction();
}
public VdcReturnValueBase EndAction(VdcActionType actionType, VdcActionParametersBase parameters) {
return endAction(actionType, parameters, null);
}
@ExcludeClassInterceptors
public VdcQueryReturnValue runInternalQuery(VdcQueryType actionType, VdcQueryParametersBase parameters) {
return runQueryImpl(actionType, parameters, false);
}
public VdcQueryReturnValue RunQuery(VdcQueryType actionType, VdcQueryParametersBase parameters) {
return runQueryImpl(actionType, parameters, true);
}
private VdcQueryReturnValue runQueryImpl(VdcQueryType actionType, VdcQueryParametersBase parameters,
boolean isPerformUserCheck) {
if (isPerformUserCheck) {
String sessionId = addSessionToContext(parameters);
if (StringHelper.isNullOrEmpty(sessionId)
|| SessionDataContainer.getInstance().GetData(sessionId, "VdcUser", parameters.getRefresh()) == null) {
VdcQueryReturnValue returnValue = new VdcQueryReturnValue();
returnValue.setSucceeded(false);
returnValue.setExceptionString(VdcBllMessages.USER_IS_NOT_LOGGED_IN.toString());
return returnValue;
}
}
QueriesCommandBase command = CommandsFactory.CreateQueryCommand(actionType, parameters);
command.Execute();
return command.getQueryReturnValue();
}
public void RunAsyncQuery(VdcQueryType actionType, VdcQueryParametersBase parameters) {
addSessionToContext(parameters);
QueriesCommandBase command = CommandsFactory.CreateQueryCommand(actionType, parameters);
command.Execute();
}
private String addSessionToContext(VdcQueryParametersBase parameters) {
String sessionId = parameters.getHttpSessionId();
boolean isAddToContext = true;
if (StringHelper.isNullOrEmpty(sessionId)) {
sessionId = parameters.getSessionId();
}
// This is a workaround for front end
// Where no session, try to get Id of session which was attached to
// request
if (StringHelper.isNullOrEmpty(sessionId)) {
sessionId = ThreadLocalParamsContainer.getHttpSessionId();
isAddToContext = false;
}
if (!StringHelper.isNullOrEmpty(sessionId) && isAddToContext) {
ThreadLocalParamsContainer.setHttpSessionId(sessionId);
}
return sessionId;
}
@Override
public java.util.ArrayList<VdcReturnValueBase> RunMultipleActions(VdcActionType actionType,
java.util.ArrayList<VdcActionParametersBase> parameters) {
return runMultipleActionsImpl(actionType, parameters, false);
}
@Override
@ExcludeClassInterceptors
public java.util.ArrayList<VdcReturnValueBase> runInternalMultipleActions(VdcActionType actionType,
java.util.ArrayList<VdcActionParametersBase> parameters) {
return runMultipleActionsImpl(actionType, parameters, true);
}
public java.util.ArrayList<VdcReturnValueBase> runMultipleActionsImpl(VdcActionType actionType,
java.util.ArrayList<VdcActionParametersBase> parameters,
boolean isInternal) {
String sessionId = ThreadLocalParamsContainer.getHttpSessionId();
if (!StringHelper.isNullOrEmpty(sessionId)) {
for (VdcActionParametersBase parameter : parameters) {
if (StringHelper.isNullOrEmpty(parameter.getSessionId())) {
parameter.setSessionId(sessionId);
}
}
}
MultipleActionsRunner runner = MultipleActionsRunnersFactory.CreateMultipleActionsRunner(actionType,
parameters, isInternal);
return runner.Execute();
}
@ExcludeClassInterceptors
public ErrorTranslator getErrorsTranslator() {
return errorsTranslator;
}
@ExcludeClassInterceptors
public ErrorTranslator getVdsErrorsTranslator() {
return _vdsErrorsTranslator;
}
/**
* Login in to the system
*
* @param parameters
* The parameters.
* @return user if success, else null // //
*/
public VdcReturnValueBase Login(LoginUserParameters parameters) {
switch (parameters.getActionType()) {
case AutoLogin:
case LoginAdminUser: {
CommandBase command = CommandsFactory.CreateCommand(parameters.getActionType(), parameters);
return command.ExecuteAction();
}
default: {
return NotAutorizedError();
}
}
}
private VdcReturnValueBase NotAutorizedError() {
VdcReturnValueBase returnValue = new VdcReturnValueBase();
returnValue.setCanDoAction(false);
returnValue.getCanDoActionMessages().add(VdcBllMessages.USER_NOT_AUTHORIZED_TO_PERFORM_ACTION.toString());
return returnValue;
}
public VdcReturnValueBase Logoff(LogoutUserParameters parameters) {
return RunAction(VdcActionType.LogoutUser, parameters);
}
/**
* @param vdsId
* @return
*/
public VDSStatus PowerUpVDS(int vdsId) {
return VDSStatus.Up;
}
/**
* @param vdsId
* @return
*/
public VDSStatus ShutDownVDS(int vdsId) {
return VDSStatus.Down;
}
public tags GetTagByTagName(String tagName) {
throw new NotImplementedException();
}
public String GetTagIdsAndChildrenIdsByRegExp(String tagNameRegExp) {
throw new NotImplementedException();
}
public String GetTagIdAndChildrenIds(int tagId) {
throw new NotImplementedException();
}
public VdcQueryReturnValue RunPublicQuery(VdcQueryType actionType, VdcQueryParametersBase parameters) {
switch (actionType) {
case GetDomainList:
case GetLicenseProperties:
case RegisterVds:
case CheckDBConnection:
return runQueryImpl(actionType, parameters, false);
case GetConfigurationValue: {
GetConfigurationValueParameters configParameters = (GetConfigurationValueParameters) parameters;
if (configParameters.getConfigValue() == ConfigurationValues.VdcVersion ||
configParameters.getConfigValue() == ConfigurationValues.ProductRPMVersion) {
return runQueryImpl(actionType, parameters, false);
} else {
VdcQueryReturnValue returnValue = new VdcQueryReturnValue();
returnValue.setSucceeded(false);
returnValue.setExceptionString(VdcBllMessages.USER_CANNOT_RUN_QUERY_NOT_PUBLIC.toString());
return returnValue;
}
}
default: {
VdcQueryReturnValue returnValue = new VdcQueryReturnValue();
returnValue.setSucceeded(false);
returnValue.setExceptionString(VdcBllMessages.USER_CANNOT_RUN_QUERY_NOT_PUBLIC.toString());
return returnValue;
}
}
}
public VdcReturnValueBase RunUserAction(VdcActionType actionType, VdcActionParametersBase parameters) {
if (StringHelper.isNullOrEmpty(parameters.getHttpSessionId())) {
return NotAutorizedError();
} else {
return RunAction(actionType, parameters);
}
}
public VdcQueryReturnValue RunUserQuery(VdcQueryType actionType, VdcQueryParametersBase parameters) {
return runQueryImpl(actionType, parameters, true);
}
public java.util.ArrayList<VdcReturnValueBase> RunUserMultipleActions(VdcActionType actionType,
java.util.ArrayList<VdcActionParametersBase> parameters) {
for (VdcActionParametersBase parameter : parameters) {
if (StringHelper.isNullOrEmpty(parameter.getHttpSessionId())) {
java.util.ArrayList<VdcReturnValueBase> returnValues = new java.util.ArrayList<VdcReturnValueBase>();
for (int i = 0; i < parameters.size(); i++) {
returnValues.add(NotAutorizedError());
}
return returnValues;
}
}
return runInternalMultipleActions(actionType, parameters);
}
public VdcReturnValueBase RunAutoAction(VdcActionType actionType, VdcActionParametersBase parameters) {
return RunAction(actionType, parameters);
}
public VdcQueryReturnValue RunAutoQuery(VdcQueryType actionType, VdcQueryParametersBase parameters) {
return runInternalQuery(actionType, parameters);
}
public AsyncQueryResults GetAsyncQueryResults() {
return BackendCallBacksDirector.getInstance().GetAsyncQueryResults();
}
private static LogCompat log = LogFactoryCompat.getLog(Backend.class);
@Override
@ExcludeClassInterceptors
public VdcReturnValueBase runInternalAction(VdcActionType actionType,
VdcActionParametersBase parameters,
CompensationContext context) {
return runActionImpl(actionType, parameters, true, context);
}
}