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

prerna.util.gson.InsightAdapter Maven / Gradle / Ivy

The newest version!
package prerna.util.gson;

import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import javax.crypto.Cipher;

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

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

import prerna.algorithm.api.ITableDataFrame;
import prerna.cache.CachePropFileFrameObject;
import prerna.cache.InsightCacheUtility;
import prerna.ds.py.PandasFrame;
import prerna.ds.r.RDataTable;
import prerna.engine.impl.SmssUtilities;
import prerna.om.Insight;
import prerna.om.InsightPanel;
import prerna.om.InsightSheet;
import prerna.om.PixelList;
import prerna.sablecc2.PixelRunner;
import prerna.sablecc2.PixelStreamUtility;
import prerna.sablecc2.PixelUtility;
import prerna.sablecc2.om.PixelDataType;
import prerna.sablecc2.om.VarStore;
import prerna.sablecc2.om.nounmeta.NounMetadata;
import prerna.sablecc2.om.task.TaskStore;
import prerna.util.Constants;
import prerna.util.Utility;
import prerna.util.insight.InsightUtility;

public class InsightAdapter extends TypeAdapter {

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

	private static final String CLASS_NAME = InsightAdapter.class.getName();
	private static final String DIR_SEPARATOR = java.nio.file.FileSystems.getDefault().getSeparator();
	
	// this var is only used so we have a way
	// to pass specific variables into a new insight we are creating from a cache
	// things like python thread
	// or potentially the full user object
	private Insight existingInsight;
	private ZipFile zip;
	
	private ZipOutputStream zos = null;
	private String folderDir = null;
	private boolean encrypt = false;
	private Cipher cipher = null;
	
	private Set varsToExclude;

	/**
	 * Constructor for reading
	 * @param zip
	 */
	public InsightAdapter(ZipFile zip) {
		this.zip = zip;
		this.varsToExclude = new HashSet<>();
	}
	
	/**
	 * Constructor for writing
	 * @param folderDir
	 * @param zos
	 */
	public InsightAdapter(String folderDir, ZipOutputStream zos) {
		this.folderDir = folderDir;
		this.zos = zos;
		this.varsToExclude = new HashSet<>();
	}
	
	@Override
	public void write(JsonWriter out, Insight value) throws IOException {
		String rdbmsId = value.getRdbmsId();
		String projectId = value.getProjectId();
		String projectName = value.getProjectName();
		
		if(projectId == null || rdbmsId == null || projectName == null) {
			throw new IOException("Cannot jsonify an insight that is not saved");
		}

		String baseFolder = Utility.getBaseFolder();
		if(!(new File(Utility.normalizePath(this.folderDir)).exists())) {
			new File(Utility.normalizePath(this.folderDir)).mkdirs();
		}
		
		// start insight object
		out.beginObject();
		// write engine id
		out.name("projectId").value(projectId);
		// write engine name
		out.name("projectName").value(projectName);
		// write rdbms id
		out.name("rdbmsId").value(rdbmsId);
		
		// write varstore
		// it is important that we write the first
		// since we use this on read for references to frames
		out.name("varstore");
		// output all variables that are not frames or tasks
		VarStoreAdapter varStoreAdapter = new VarStoreAdapter();
		varStoreAdapter.setKeysToIgnore(this.varsToExclude);
		varStoreAdapter.setCollectFrames(true);
		VarStore varStore = value.getVarStore();
		varStoreAdapter.write(out, varStore);
		
		// for optimization
		// we collected the frames during the above adapter writing
		// it also ignores the keys based on varsToExclude
		List frames = varStoreAdapter.getFrames();
		
		// now that we have consolidated, write the frames
		out.name("frames");
		out.beginArray();
		for(FrameCacheHelper fObj : frames) {
			// set the logger for this frame
			fObj.getFrame().setLogger(classLogger);
			CachePropFileFrameObject saveFrame = fObj.getFrame().save(this.folderDir, this.cipher);
			out.beginObject();
			out.name("file").value(parameterizePath(saveFrame.getFrameCacheLocation(), baseFolder, projectName, projectId));
			out.name("meta").value(parameterizePath(saveFrame.getFrameMetaCacheLocation(), baseFolder, projectName, projectId));
			out.name("state").value(parameterizePath(saveFrame.getFrameStateCacheLocation(), baseFolder, projectName, projectId));
			out.name("type").value(saveFrame.getFrameType());
			out.name("name").value(saveFrame.getFrameName());
			out.name("keys");
			out.beginArray();
			List alias = fObj.getAlias();
			for(int i = 0; i < alias.size(); i++) {
				out.value(alias.get(i));
			}
			out.endArray();
			out.endObject();
			
			// add to zip
			File f1 = new File(Utility.normalizePath(saveFrame.getFrameCacheLocation()));
			File f2 = new File(Utility.normalizePath(saveFrame.getFrameMetaCacheLocation()));

			try {
				InsightCacheUtility.addToZipFile(f1, zos);
				InsightCacheUtility.addToZipFile(f2, zos);
			} catch(Exception e) {
				classLogger.error(Constants.STACKTRACE, e);
			}
		}
		out.endArray();
		
		// write the sheets
		out.name("sheets");
		out.beginArray();
		Map sheets = value.getInsightSheets();
		for(String key : sheets.keySet()) {
			InsightSheet sheet = sheets.get(key);
			InsightSheetAdapter sheetAdapter = new InsightSheetAdapter();
			sheetAdapter.write(out, sheet);
		}
		out.endArray();
		
		// write the panels
		out.name("panels");
		out.beginArray();
		Map panels = value.getInsightPanels();
		for(String key : panels.keySet()) {
			InsightPanel panel = panels.get(key);
			InsightPanelAdapter panelAdapter = new InsightPanelAdapter();
			panelAdapter.write(out, panel);
		}
		out.endArray();

		// this is not written
		// but need to store the refresh panel task ids
		// get the last task at each layer for each panel
		// this will be written to the vizOutputFile
		Insight cachedInsight = new Insight();
		// TODO: this is because the BE adds a default sheet for new insights
		// but this is not required for cached insights
		cachedInsight.getInsightSheets().clear();
		InsightUtility.transferDefaultVars(value, cachedInsight);
		cachedInsight.setVarStore(value.getVarStore());
		cachedInsight.setUser(value.getUser());
		cachedInsight.setInsightSheets(value.getInsightSheets());
		cachedInsight.setInsightPanels(value.getInsightPanels());
		// make sure the task ids do not overlap
		cachedInsight.setTaskStore(value.getTaskStore());
		List cachedRecipe = PixelUtility.getCachedInsightRecipe(value);
		PixelRunner pixelRunner = cachedInsight.runPixel(cachedRecipe);
		
		// write the tasks
		out.name("tasks");
		TaskStore tStore = value.getTaskStore();
		TaskStoreAdapter tAdapter = new TaskStoreAdapter();
		tAdapter.write(out, tStore);
		
		// write the recipe
		PixelList pixelList = value.getPixelList();
		out.name("recipe");
		PixelListAdapter pAdapter = new PixelListAdapter();
		pAdapter.write(out, pixelList);
		
		// end insight object
		out.endObject();
		
		// this is no longer part of the actual 
		// insight serialization
		// but writing things to disk
		
		// write the json for the viz
		// this doesn't actually add anything to the insight object
		File vizOutputFile = new File(Utility.normalizePath(this.folderDir) + DIR_SEPARATOR + InsightCacheUtility.VIEW_JSON);
		// lets write it
		PixelStreamUtility.writePixelData(pixelRunner, vizOutputFile, this.cipher);
		
		// add it to the zip
		try {
			InsightCacheUtility.addToZipFile(vizOutputFile, zos);
		} catch(Exception e) {
			classLogger.error(Constants.STACKTRACE, e);
		}
	}
	
	@Override
	public Insight read(JsonReader in) throws IOException {
		String baseFolder = Utility.getBaseFolder();

		Insight insight = new Insight();
		// TODO: this is because the BE adds a default sheet for new insights
		// but this is not required for cached insights
		insight.getInsightSheets().clear();
		
		in.beginObject();
		in.nextName();
		// engine id, engine name, rdbms id
		String projectId = in.nextString();
		insight.setProjectId(projectId);
		in.nextName();
		String projectName = in.nextString();
		insight.setProjectName(projectName);
		in.nextName();
		String rdbmsId = in.nextString();
		insight.setRdbmsId(rdbmsId);
		
		// this will be the varstore
		in.nextName();
		VarStoreAdapter varStoreAdapter = new VarStoreAdapter();
		VarStore store = varStoreAdapter.read(in);
		if(store != null) {
			insight.setVarStore(store);
		}
		if(this.existingInsight != null) {
			InsightUtility.transferDefaultVars(this.existingInsight, insight);
		}
		
		// this will be the frames
		in.nextName();
		in.beginArray();
		while(in.hasNext()) {
			in.beginObject();
			
			List varStoreKeys = new Vector<>();
			CachePropFileFrameObject cf = new CachePropFileFrameObject();
			while(in.hasNext()) {
				String k = in.nextName();
				if(k.equals("file")) {
					String path = deparameterizePath(in.nextString(), baseFolder, projectName, projectId);
					String normalizedPath = Utility.normalizePath(path);

					if(!(new File(normalizedPath).exists())) {
						InsightCacheUtility.unzipFile(zip, FilenameUtils.getName(normalizedPath), normalizedPath);
					}
					cf.setFrameCacheLocation(path);
				} else if(k.equals("meta")) {
					String path = deparameterizePath(in.nextString(), baseFolder, projectName, projectId);
					String normalizedPath = Utility.normalizePath(path);

					if(!(new File(normalizedPath).exists())) {
						InsightCacheUtility.unzipFile(zip, FilenameUtils.getName(normalizedPath), normalizedPath);
					}
					cf.setFrameMetaCacheLocation(normalizedPath);
				} else if(k.equals("type")) {
					cf.setFrameType(in.nextString());
				} else if(k.equals("name")) {
					cf.setFrameName(in.nextString());
				} else if(k.equals("state")) {
					// this is not always present
					JsonToken peek = in.peek();
					if(peek == JsonToken.NULL) {
						in.nextNull();
					} else {
						String path = deparameterizePath(in.nextString(), baseFolder, projectName, projectId);
						String normalizedPath = Utility.normalizePath(path);

						if(!(new File(normalizedPath).exists())) {
							InsightCacheUtility.unzipFile(zip, FilenameUtils.getName(normalizedPath), normalizedPath);
						}
						cf.setFrameStateCacheLocation(normalizedPath);
					}
				} else if(k.equals("keys")) {
					in.beginArray();
					while(in.hasNext()) {
						varStoreKeys.add(in.nextString());
					}
					in.endArray();
				}
			}

			ITableDataFrame frame;
			try {
				String className = cf.getFrameType();
				frame = (ITableDataFrame) Class.forName(className).newInstance();
				// need to set the exector for pandas
				if(frame instanceof PandasFrame) {
					((PandasFrame)frame).setTranslator(insight.getPyTranslator());
				}
				else if(frame instanceof RDataTable) {
					frame = new RDataTable(insight.getRJavaTranslator(CLASS_NAME));
				}
				
				frame.open(cf, this.cipher);
				
				NounMetadata fNoun = new NounMetadata(frame, PixelDataType.FRAME);
				for(String varStoreK : varStoreKeys) {
					store.put(varStoreK, fNoun);
				}
			} catch (InstantiationException e) {
				classLogger.error(Constants.STACKTRACE, e);
			} catch (IllegalAccessException iae) {
				classLogger.error(Constants.STACKTRACE, iae);
			} catch (ClassNotFoundException cnfe) {
				classLogger.error(Constants.STACKTRACE, cnfe);
			}
			
			in.endObject();
		}
		in.endArray();

		// this will be the sheets
		// need to account for legacy
		String sheetKey = in.nextName();
		if(sheetKey.equals("sheets")) {
			in.beginArray();
			while(in.hasNext()) {
				InsightSheetAdapter sheetAdapter = new InsightSheetAdapter();
				sheetAdapter.setInsight(insight);
				InsightSheet sheet = sheetAdapter.read(in);
				insight.addNewInsightSheet(sheet);
			}
			in.endArray();
			
			// this will be the panels
			in.nextName();
			in.beginArray();
			while(in.hasNext()) {
				InsightPanelAdapter panelAdapter = new InsightPanelAdapter();
				panelAdapter.setInsight(insight);
				InsightPanel panel = panelAdapter.read(in);
				insight.addNewInsightPanel(panel);
			}
			in.endArray();
		} else {
			// this is legacy where we only have panels and no sheets
			// just load the sheets
			in.beginArray();
			while(in.hasNext()) {
				InsightPanelAdapter panelAdapter = new InsightPanelAdapter();
				panelAdapter.setInsight(insight);
				InsightPanel panel = panelAdapter.read(in);
				insight.addNewInsightPanel(panel);
			}
			in.endArray();
		}
		
		// this will be the tasks
		in.nextName();
		TaskStoreAdapter tStoreAdapter = new TaskStoreAdapter();
		tStoreAdapter.setInsight(insight);
		TaskStore tStore = tStoreAdapter.read(in);
		insight.setTaskStore(tStore);
		
		// this will be the recipe
		in.nextName();
		PixelListAdapter pAdapter = new PixelListAdapter();
		pAdapter.setInsight(insight);
		PixelList pixelList = pAdapter.read(in);
		insight.setPixelList(pixelList);
		
		in.endObject();
		return insight;
	}

	private static String parameterizePath(String path, String baseFolder, String engineName, String engineId) {
		if(path == null) {
			return null;
		}
		
		// we want to keep the final / in the path
		if(baseFolder.endsWith("/") || baseFolder.endsWith("\\")) {
			baseFolder = baseFolder.substring(0, baseFolder.length()-1);
		}
		
		path = path.replace(baseFolder, "@" + Constants.BASE_FOLDER + "@");
		path = path.replace(SmssUtilities.getUniqueName(engineName, engineId), "@" + Constants.ENGINE + "@");
		return path;
	}
	
	private static String deparameterizePath(String path, String baseFolder, String engineName, String engineId) {
		if(path == null) {
			return null;
		}
		
		// if we have a separator in the parameterized path
		// we do not want a separator in baseFolder
		// if there is no separator in the parameterized path
		// then we do want a separator in baseFolder
		
		// separator parameterized path 
		if(path.contains("@" + Constants.BASE_FOLDER + "@\\") || path.contains("@" + Constants.BASE_FOLDER + "@/")) {
			if(baseFolder.endsWith("/") || baseFolder.endsWith("\\")) {
				baseFolder = baseFolder.substring(0, baseFolder.length()-1);
			}
		}
		// no separator in parameterized path
		else {
			if(!baseFolder.endsWith("/") && !baseFolder.endsWith("\\")) {
				baseFolder += DIR_SEPARATOR;
			}
		}
		
		path = path.replace("@" + Constants.BASE_FOLDER + "@", baseFolder);
		path = path.replace("@" + Constants.ENGINE + "@", SmssUtilities.getUniqueName(engineName, engineId));
		return path;
	}

	public void setUserContext(Insight existingInsight) {
		this.existingInsight = existingInsight;		
	}
	
	public void setVarsToExclude(Set varsToExclude) {
		this.varsToExclude = varsToExclude;
	}

	public boolean isEncrypt() {
		return encrypt;
	}

	public void setEncrypt(boolean encrypt) {
		this.encrypt = encrypt;
	}

	public Cipher getCipher() {
		return cipher;
	}

	public void setCipher(Cipher cipher) {
		this.cipher = cipher;
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy