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

prerna.reactor.database.upload.AbstractDatabaseUploadFileReactor Maven / Gradle / Ivy

The newest version!
package prerna.reactor.database.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.IDatabaseEngine;
import prerna.engine.api.IEngine;
import prerna.masterdatabase.utility.MasterDatabaseUtility;
import prerna.project.api.IProject;
import prerna.reactor.AbstractReactor;
import prerna.sablecc2.om.PixelDataType;
import prerna.sablecc2.om.PixelOperationType;
import prerna.sablecc2.om.execptions.SemossPixelException;
import prerna.sablecc2.om.nounmeta.NounMetadata;
import prerna.util.Constants;
import prerna.util.UploadInputUtility;
import prerna.util.UploadUtilities;
import prerna.util.Utility;

public abstract class AbstractDatabaseUploadFileReactor extends AbstractReactor {

	private static final Logger classLogger = LogManager.getLogger(AbstractDatabaseUploadFileReactor.class);
	
	/**
	 * Every reactor that extends this needs to define its own inputs
	 * However, every one needs to have the following in the keysToGet array:
	 * UploadUtility.DATABASE
	 * UploadInputUtility.FILE_PATH
	 * UploadInputUtility.ADD_TO_EXISTING
	 * 
	 */
	
	// we need to define some variables that are stored at the class level
	// so that we can properly account for cleanup if errors occur
	protected transient Logger logger;
	protected transient String databaseId;
	protected transient String databaseName;
	protected transient IDatabaseEngine database;
	protected transient IProject project;
	protected transient File databaseFolder;
	protected transient File tempSmss;
	protected transient File smssFile;
	
	protected transient boolean error = false;
	
	@Override
	public NounMetadata execute() {
		this.logger = getLogger(this.getClass().getName());

		organizeKeys();
		String databaseIdOrName = UploadInputUtility.getDatabaseNameOrId(this.store);
		String filePath = UploadInputUtility.getFilePath(this.store, this.insight);
		if (!new File(filePath).exists()) {
			throw new IllegalArgumentException("Could not find the specified file to use for importing");
		}
		final boolean existing = UploadInputUtility.getExisting(this.store);
		// check security
		User user = this.insight.getUser();
		if (user == null) {
			NounMetadata noun = new NounMetadata("User must be signed into an account in order to create or update a database", PixelDataType.CONST_STRING, PixelOperationType.ERROR, PixelOperationType.LOGGIN_REQUIRED_ERROR);
			SemossPixelException err = new SemossPixelException(noun);
			err.setContinueThreadOfExecution(false);
			throw err;
		}
		
		// throw error if user is anonymous
		if (AbstractSecurityUtils.anonymousUsersEnabled() && 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.adminOnlyDatabaseAdd() && !SecurityAdminUtils.userIsAdmin(user)) {
			throwFunctionalityOnlyExposedForAdminsError();
		}

		if (existing) {
			// check if input is alias since we are adding ot existing
			databaseIdOrName = SecurityQueryUtils.testUserEngineIdForAlias(user, databaseIdOrName);
			if (!SecurityEngineUtils.userCanEditEngine(user, databaseIdOrName)) {
				NounMetadata noun = new NounMetadata("User does not have sufficient priviledges to create or update a database", PixelDataType.CONST_STRING, PixelOperationType.ERROR);
				SemossPixelException err = new SemossPixelException(noun);
				err.setContinueThreadOfExecution(false);
				throw err;
			}

			try {
				this.databaseId = databaseIdOrName;
				this.databaseName = MasterDatabaseUtility.getDatabaseAliasForId(this.databaseId);
				// get existing database
				this.logger.info("Get existing database");
				this.database = Utility.getDatabase(databaseId);
				if (this.database == null) {
					throw new IllegalArgumentException("Couldn't find the database " + databaseId + " to append data into");
				}
				this.logger.info("Done");
				addToExistingDatabase(filePath);
				// sync metadata
				this.logger.info("Process database metadata to allow for traversing across databases");
				UploadUtilities.updateMetadata(this.database.getEngineId(), user);
				this.logger.info("Complete");
				this.logger.info("Delete OWL position map");
				File owlF = this.database.getOwlPositionFile();
				if(owlF.exists()) {
					owlF.delete();
				}
				this.logger.info("Complete");
			} catch (Exception e) {
				classLogger.error(Constants.STACKTRACE, e);
				this.error = true;
				if (e instanceof SemossPixelException) {
					throw (SemossPixelException) e;
				} else {
					NounMetadata noun = new NounMetadata(e.getMessage(), PixelDataType.CONST_STRING,
							PixelOperationType.ERROR);
					SemossPixelException err = new SemossPixelException(noun);
					err.setContinueThreadOfExecution(false);
					throw err;
				}
			} finally {
				closeFileHelpers();
				// need to rollback
				// TODO:
			}
		} else {
			try {
				// make a new id
				this.databaseId = UUID.randomUUID().toString();
				this.databaseName = databaseIdOrName;
				// validate database
				this.logger.info("Start validating database");
				UploadUtilities.validateEngine(IEngine.CATALOG_TYPE.DATABASE, user, this.databaseName, this.databaseId);
				this.logger.info("Done validating database");
				// create database folder
				this.logger.info("Start generating database folder");
				this.databaseFolder = UploadUtilities.generateSpecificEngineFolder(IEngine.CATALOG_TYPE.DATABASE, this.databaseId, this.databaseName);
				this.logger.info("Complete");
				generateNewDatabase(user, this.databaseName, filePath);
				// and rename .temp to .smss
				this.smssFile = new File(this.tempSmss.getAbsolutePath().replace(".temp", ".smss"));
				FileUtils.copyFile(this.tempSmss, this.smssFile);
				this.tempSmss.delete();
				this.database.setSmssFilePath(this.smssFile.getAbsolutePath());
				UploadUtilities.updateDIHelper(this.databaseId, this.databaseName, this.database, this.smssFile);
				// sync metadata
				this.logger.info("Process database metadata to allow for traversing across databases");
				UploadUtilities.updateMetadata(this.databaseId, user);
				
				// adding all the git here
				// make a version folder if one doesn't exist
				/*
					String versionFolder = 	AssetUtility.getAppAssetVersionFolder(databaseName, databaseId);
					File file = new File(versionFolder);
					if(!file.exists())
						file.mkdir();
					// I will assume the directory is there now
					GitRepoUtils.init(versionFolder);
				*/
				
				this.logger.info("Complete");
			} catch (Exception e) {
				classLogger.error(Constants.STACKTRACE, e);
				this.error = true;
				if (e instanceof SemossPixelException) {
					throw (SemossPixelException) e;
				} else {
					NounMetadata noun = new NounMetadata(e.getMessage(), PixelDataType.CONST_STRING, PixelOperationType.ERROR);
					SemossPixelException err = new SemossPixelException(noun);
					err.setContinueThreadOfExecution(false);
					throw err;
				}
			} finally {
				closeFileHelpers();
				if (this.error) {
					// need to delete everything...
					cleanUpCreateNewError();
				}
			}

			// even if no security, just add user as database owner
			if (user != null) {
				List logins = user.getLogins();
				for (AuthProvider ap : logins) {
					SecurityEngineUtils.addEngineOwner(this.databaseId, user.getAccessToken(ap).getId());
				}
			}
		}

		// if we got here
		// no errors
		// we can do normal clean up of files
		// TODO:

		ClusterUtil.pushEngine(this.databaseId);

		Map retMap = UploadUtilities.getEngineReturnData(this.insight.getUser(), this.databaseId);
		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() {
		try {
			// close the DB so we can delete it
			if (this.database != null) {
				database.close();
			}

			// delete the .temp file
			if (this.tempSmss != null && this.tempSmss.exists()) {
				FileUtils.forceDelete(this.tempSmss);
			}
			// delete the .smss file
			if (this.smssFile != null && this.smssFile.exists()) {
				FileUtils.forceDelete(this.smssFile);
			}
			// delete the database folder and all its contents
			if (this.databaseFolder != null && this.databaseFolder.exists()) {
				File[] files = this.databaseFolder.listFiles();
				if (files != null) { // some JVMs return null for empty dirs
					for (File f : files) {
						FileUtils.forceDelete(f);
					}
				}
				FileUtils.forceDelete(this.databaseFolder);
			}
			
			UploadUtilities.removeEngineFromDIHelper(this.databaseId);
		} catch (Exception e) {
			classLogger.error(Constants.STACKTRACE, e);
		}
	}

	///////////////////////////////////////////////////////

	/*
	 * Execution methods
	 * This will be done by every implementation of the upload file reactors
	 */

	public abstract void generateNewDatabase(User user, final String newDatabaseName, final String filePath) throws Exception;

	public abstract void addToExistingDatabase(final String filePath) throws Exception;

	public abstract void closeFileHelpers();
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy