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

com.xdev.jadoth.codegen.java.JavaRuntimeCompiler Maven / Gradle / Ivy

/*
 * XDEV Application Framework - XDEV Application Framework
 * Copyright © 2003 XDEV Software (https://xdev.software)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 */
package com.xdev.jadoth.codegen.java;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

import com.xdev.jadoth.Jadoth;


/**
 * The Class JavaRuntimeCompiler.
 */
public class JavaRuntimeCompiler {

	/** The javac. */
	private final JavaCompiler javac;

	/** The src folder. */
	private File srcFolder;

	/** The bin folder. */
	private File binFolder;

	/** The file suffix. */
	private String fileSuffix = "java";


	/**
	 * Gets the file suffix.
	 *
	 * @return the fileSuffix
	 */
	public String getFileSuffix() {
		return this.fileSuffix;
	}


	/**
	 * Sets the file suffix.
	 *
	 * @param fileSuffix the fileSuffix to set
	 */
	public void setFileSuffix(final String fileSuffix) {
		this.fileSuffix = fileSuffix;
	}


	/**
	 * Instantiates a new java runtime compiler.
	 */
	public JavaRuntimeCompiler(){
		this.javac = ToolProvider.getSystemJavaCompiler();
		if(this.javac == null) {
			throw new NullPointerException("System Java Compiler not found. Check for JDK and build path.");
		}
		this.srcFolder = null;
		this.binFolder = null;
	}


	/**
	 * Gets the src folder.
	 *
	 * @return the src folder
	 */
	public File getSrcFolder() {
		return this.srcFolder;
	}


	/**
	 * Sets the src folder.
	 *
	 * @param srcFolder the new src folder
	 */
	public void setSrcFolder(final String srcFolder) {
		File newFile;
		try {
			newFile = new File(srcFolder);
		} catch (final Exception e) {
			this.srcFolder = null;
			return;
		}

		if(newFile.isAbsolute()) {
			this.srcFolder = newFile;
		}
	}


	/**
	 * Gets the bin folder.
	 *
	 * @return the bin folder
	 */
	public File getBinFolder() {
		return this.binFolder;
	}


	/**
	 * Sets the bin folder.
	 *
	 * @param binFolder the new bin folder
	 */
	public void setBinFolder(final String binFolder) {
		File newFile;
		try {
			newFile = new File(binFolder);
		} catch (final Exception e) {
			this.binFolder = null;
			return;
		}

		if(newFile.isAbsolute()) {
			this.binFolder = newFile;
		}
	}



	/**
	 * Write class file.
	 *
	 * @param code the code
	 * @param filename the filename
	 * @param compile the compile
	 * @return the compiler status code
	 */
	public final CompilerStatusCode writeClassFile(final String code, final String filename, final boolean compile)
	{
		if(this.srcFolder == null) {
			throw new RuntimeException("Error: no valid src folder given.");
		}
		if(compile && this.binFolder == null) {
			throw new RuntimeException("Error: no valid bin folder given.");
		}

		Jadoth.ensureFolder(this.srcFolder);
		if(compile){
			Jadoth.ensureFolder(this.binFolder);
		}
		final File sourceFile = Jadoth.ensureWritableFile(this.srcFolder, filename + '.'+this.fileSuffix);
		final String sourceFileString = sourceFile.getAbsolutePath();

		if(!this.writeSourceFile(code, sourceFile)) {
			throw new RuntimeException("Error: Could not write file "+sourceFile);
		}

		if(!compile || !this.fileSuffix.toLowerCase().equals("java")){
			return new CompilerStatusCode("File "+sourceFileString+" written successfully (uncompiled).");
		}

		final File classFolder = Jadoth.ensureFolder(this.binFolder);
		final String classFolderString = classFolder.getAbsolutePath();

		if(classFolder == null) {
			throw new RuntimeException("Error: Could not reach folder "+classFolderString);
		}

		final ByteArrayOutputStream errorOutput = new ByteArrayOutputStream();


		final int returnCode = this.javac.run(null, null, errorOutput, "-d", this.binFolder.getAbsolutePath(), sourceFileString);
		boolean success = false;
		if(returnCode == 0){
			success = true;
		}

		if(success){
			return new CompilerStatusCode(returnCode, "File "+sourceFileString+" compiled successfully.");
		}
		sourceFile.delete();
		classFolder.delete();
		return new CompilerStatusCode(returnCode, "Error: \n"+errorOutput.toString());
	}


	/**
	 * Compile.
	 *
	 * @param code the code
	 * @param filename the filename
	 * @return the compiler status code
	 */
	public final CompilerStatusCode compile(final String code, final String filename){
		return this.writeClassFile(code, filename, true);
	}




	/**
	 * Write source file.
	 *
	 * @param code the code
	 * @param sourceFile the source file
	 * @return true, if successful
	 */
	protected boolean writeSourceFile(final String code, final File sourceFile){
		try {
			sourceFile.createNewFile();
		} catch (final Exception e) {
			return false;
		}

		if(sourceFile.canWrite()){
			try(FileWriter sourceWriter = new FileWriter(sourceFile)) {
				sourceWriter.write(code);
			} catch (final IOException e) {
				sourceFile.delete();
				return false;
			}
		}
		else {
			return false;
		}
		return true;
	}


	/**
	 * The Class CompilerStatusCode.
	 */
	public static class CompilerStatusCode
	{

		/** The return code. */
		final private int returnCode;

		/** The message. */
		final private String message;

		/** The success. */
		final private boolean success;

		/**
		 * Instantiates a new compiler status code.
		 *
		 * @param message the message
		 */
		private CompilerStatusCode(final String message) {
			this(0, message);
		}

		/**
		 * Instantiates a new compiler status code.
		 *
		 * @param returnCode the return code
		 * @param message the message
		 */
		private CompilerStatusCode(final int returnCode, final String message) {
			super();
			this.returnCode = returnCode;
			this.message = message;
			this.success = returnCode == 0; //javac returns 0 for success
		}

		/**
		 * Gets the return code.
		 *
		 * @return the returnCode
		 */
		public Integer getReturnCode() {
			return this.returnCode;
		}

		/**
		 * Gets the message.
		 *
		 * @return the message
		 */
		public String getMessage() {
			return this.message;
		}

		/**
		 * Checks if is success.
		 *
		 * @return the success
		 */
		public boolean isSuccess() {
			return this.success;
		}

		/**
		 * To string.
		 *
		 * @return the string
		 * @return
		 */
		@Override
		public String toString() {
			return "Code("+this.returnCode+"): "+this.message;
		}


	}


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy