All Downloads are FREE. Search and download functionalities are using the official Maven repository.

prerna.reactor.model.upload.CreateModelEngineReactor Maven / Gradle / Ivy

The newest version!
package prerna.reactor.model.upload;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import prerna.auth.AuthProvider;
import prerna.auth.User;
import prerna.auth.utils.AbstractSecurityUtils;
import prerna.auth.utils.SecurityAdminUtils;
import prerna.auth.utils.SecurityEngineUtils;
import prerna.auth.utils.SecurityQueryUtils;
import prerna.cluster.util.ClusterUtil;
import prerna.engine.api.IEngine;
import prerna.engine.api.IModelEngine;
import prerna.engine.api.ModelTypeEnum;
import prerna.reactor.AbstractReactor;
import prerna.sablecc2.om.GenRowStruct;
import prerna.sablecc2.om.PixelDataType;
import prerna.sablecc2.om.PixelOperationType;
import prerna.sablecc2.om.ReactorKeysEnum;
import prerna.sablecc2.om.execptions.SemossPixelException;
import prerna.sablecc2.om.nounmeta.NounMetadata;
import prerna.util.Constants;
import prerna.util.DIHelper;
import prerna.util.PythonVariableValidator;
import prerna.util.Settings;
import prerna.util.UploadUtilities;
import prerna.util.Utility;

public class CreateModelEngineReactor extends AbstractReactor {

	private static final Logger classLogger = LogManager.getLogger(CreateModelEngineReactor.class);

	public CreateModelEngineReactor() {
		this.keysToGet = new String[] {ReactorKeysEnum.MODEL.getKey(), ReactorKeysEnum.MODEL_DETAILS.getKey(), ReactorKeysEnum.GLOBAL.getKey()};
	}
	
	@Override
	public NounMetadata execute() {
		User user = this.insight.getUser();
		if (user == null) {
			NounMetadata noun = new NounMetadata(
					"User must be signed into an account in order to create a model engine", PixelDataType.CONST_STRING,
					PixelOperationType.ERROR, PixelOperationType.LOGGIN_REQUIRED_ERROR);
			SemossPixelException err = new SemossPixelException(noun);
			err.setContinueThreadOfExecution(false);
			throw err;
		}

		if (AbstractSecurityUtils.anonymousUsersEnabled()) {
			if (this.insight.getUser().isAnonymous()) {
				throwAnonymousUserError();
			}
		}

		// throw error is user doesn't have rights to publish new databases
		if (AbstractSecurityUtils.adminSetPublisher()
				&& !SecurityQueryUtils.userIsPublisher(this.insight.getUser())) {
			throwUserNotPublisherError();
		}

		if (AbstractSecurityUtils.adminOnlyModelAdd() && !SecurityAdminUtils.userIsAdmin(user)) {
			throwFunctionalityOnlyExposedForAdminsError();
		}

		organizeKeys();
		
		String modelName = getModelName();
		//if model name is not valid, throw error
		if (!Utility.validateName(modelName)) {
			//error and redirect to try again
			throw new IllegalArgumentException("Invalid Name: It must start with a letter and can only contain letters, numbers, and spaces.");
		}
		
		//String modelName = getModelName();
		Map modelDetails = getModelDetails();
		boolean global = Boolean.parseBoolean(this.keyValue.get(ReactorKeysEnum.GLOBAL.getKey())+"");

		String modelTypeStr = (String) modelDetails.get(IModelEngine.MODEL_TYPE);
		if(modelTypeStr == null || (modelTypeStr=modelTypeStr.trim()).isEmpty()) {
			throw new IllegalArgumentException("Must define the model type");
		}
		ModelTypeEnum modelType = null;
		try {
			modelType = ModelTypeEnum.getEnumFromName(modelTypeStr);
		} catch(Exception e) {
			throw new IllegalArgumentException("Invalid model type " + modelTypeStr);
		}
		
		if(modelDetails.containsKey(Settings.VAR_NAME)) {
			// need to validate this is alphanumeric underscore and does not start with a number
			String varName = (String) modelDetails.get(Settings.VAR_NAME);
			if(!PythonVariableValidator.isValidPythonVariableName(varName)) {
				throw new IllegalArgumentException("The variable '"+varName+"' is not a valid variable name. It must be alphanumeric underscore, cannot start with a digit, and cannot be a reserved word.");
			}
		}
		
		String modelId = UUID.randomUUID().toString();
		File tempSmss = null;
		File smssFile = null;
		File specificEngineFolder = null;
		IModelEngine model = null;
		try {
			// validate engine
			UploadUtilities.validateEngine(IEngine.CATALOG_TYPE.MODEL, user, modelName, modelId);
			specificEngineFolder = UploadUtilities.generateSpecificEngineFolder(IEngine.CATALOG_TYPE.MODEL, modelId, modelName);
			
			String modelClass = modelType.getModelClass();
			model = (IModelEngine) Class.forName(modelClass).newInstance();
			tempSmss = UploadUtilities.createTemporaryModelSmss(modelId, modelName, modelClass, modelDetails);
			
			// store in DIHelper so that when we move temp smss to smss it doesn't try to reload again
			DIHelper.getInstance().setEngineProperty(modelId + "_" + Constants.STORE, tempSmss.getAbsolutePath());
			model.open(tempSmss.getAbsolutePath());			
			
			smssFile = new File(tempSmss.getAbsolutePath().replace(".temp", ".smss"));
			FileUtils.copyFile(tempSmss, smssFile);
			tempSmss.delete();
			model.setSmssFilePath(smssFile.getAbsolutePath());
			UploadUtilities.updateDIHelper(modelId, modelName, model, smssFile);
			SecurityEngineUtils.addEngine(modelId, global, user);
			
			// even if no security, just add user as database owner
			if (user != null) {
				List logins = user.getLogins();
				for (AuthProvider ap : logins) {
					SecurityEngineUtils.addEngineOwner(modelId, user.getAccessToken(ap).getId());
				}
			}
			
			ClusterUtil.pushEngine(modelId);
		} catch(Exception e) {
			classLogger.error(Constants.STACKTRACE, e);
			cleanUpCreateNewError(model, modelId, tempSmss, smssFile, specificEngineFolder);
		}
		
		Map retMap = UploadUtilities.getEngineReturnData(this.insight.getUser(), modelId);
		return new NounMetadata(retMap, PixelDataType.UPLOAD_RETURN_MAP, PixelOperationType.MARKET_PLACE_ADDITION);
	}
	
	/**
	 * Delete all the corresponding files that are generated from the upload the failed
	 */
	private void cleanUpCreateNewError(IModelEngine model, String modelId, File tempSmss, File smssFile, File specificEngineFolder) {
		try {
			// close the DB so we can delete it
			if (model != null) {
				model.close();
			}

			// delete the .temp file
			if (tempSmss != null && tempSmss.exists()) {
				FileUtils.forceDelete(tempSmss);
			}
			// delete the .smss file
			if (smssFile != null && smssFile.exists()) {
				FileUtils.forceDelete(smssFile);
			}
			if (specificEngineFolder != null && specificEngineFolder.exists()) {
				FileUtils.forceDelete(specificEngineFolder);
			}
			
			UploadUtilities.removeEngineFromDIHelper(modelId);
		} catch (Exception e) {
			classLogger.error(Constants.STACKTRACE, e);
		}
	}
	
	/**
	 * 
	 * @return
	 */
	private String getModelName() {
		GenRowStruct grs = this.store.getNoun(ReactorKeysEnum.MODEL.getKey());
		if(grs != null && !grs.isEmpty()) {
			List strValues = grs.getAllStrValues();
			if(strValues != null && !strValues.isEmpty()) {
				return strValues.get(0).trim();
			}
		}
		
		List strValues = this.curRow.getAllStrValues();
		if(strValues != null && !strValues.isEmpty()) {
			return strValues.get(0).trim();
		}
		
		throw new NullPointerException("Must define the name of the new model engine");
	}
	
	/**
	 * 
	 * @return
	 */
	private Map getModelDetails() {
		GenRowStruct grs = this.store.getNoun(ReactorKeysEnum.MODEL_DETAILS.getKey());
		if(grs != null && !grs.isEmpty()) {
			List mapNouns = grs.getNounsOfType(PixelDataType.MAP);
			if(mapNouns != null && !mapNouns.isEmpty()) {
				return (Map) mapNouns.get(0).getValue();
			}
		}
		
		List mapNouns = this.curRow.getNounsOfType(PixelDataType.MAP);
		if(mapNouns != null && !mapNouns.isEmpty()) {
			return (Map) mapNouns.get(0).getValue();
		}
		
		throw new NullPointerException("Must define the properties for the new model engine");
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy