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

jsclassloader.Bundler Maven / Gradle / Ivy

package jsclassloader;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import jsclassloader.classes.ClassFileSet;
import jsclassloader.dependency.ClassNode;
import jsclassloader.dependency.DependencyGraph;

public class Bundler {
	
	private final static Logger LOG = Logger.getLogger("JS-Class-Loader");
	
	private List classList;
	private Iterator iterator;
	private ClassNode currentNode;
	private ClassFileSet classFileSet;
	private int contentLength;
	private Map addedClasses;
	private DependencyGraph dependencyGraph;
	private List seedClassNameList;
	
	public List getClassList() {
		return classList;
	}

	public Bundler(Config config) throws IOException {
		classList = new LinkedList();

		this.dependencyGraph = new DependencyGraph(config);
		seedClassNameList = new ArrayList();
		addedClasses = new HashMap();
		
		String propAllClasses = config.getProperty(Config.PROP_ALL_CLASSES);
		if (propAllClasses != null && propAllClasses.toLowerCase().equals("true")) {
			classFileSet = dependencyGraph.getClassFileSet();
			for (String className : classFileSet.getAllJsClasses()) {
				addNode(dependencyGraph.getNode(className), classList);
			}
		}
		else {

			String seedClassString = config.getProperty(Config.PROP_SEED_CLASSES);
			if (seedClassString != null) {
				String[] seedClasses = seedClassString.split(",");
				
				for (String className : seedClasses) {
					ClassNode node = dependencyGraph.getNode(className);
					if (node == null) {
						throw new RuntimeException(
								"Error, you have specified a seed class that doesn't exist or isn't in the correct file location: "
										+ className);
					}
					seedClassNameList.add(className);
					addNode(dependencyGraph.getNode(className), classList);
				}
			}
			if (config.getProperty(Config.PROP_SEED_FILES) != null) {
				try {
					List seedFileClasses = dependencyGraph
							.getSeedClassesFromFiles(generateSeedFileList(config));

					for (String seedFileClass : seedFileClasses) {
						seedClassNameList.add(seedFileClass);
						addNode(dependencyGraph.getNode(seedFileClass), classList);
					}
				} catch (IOException e) {
					throw new RuntimeException("error parsing seed files: " + e);
				}
			}
		}
		
		iterator = classList.listIterator();
		classFileSet = dependencyGraph.getClassFileSet();

		contentLength = 0;
		while (iterator.hasNext()) {
			File file = classFileSet.getFileFromClassname(iterator.next()
					.getValue());
			contentLength += file.length();
			contentLength += ("\n\n//File: " + file.getPath() + "\n").length();
		}
	}

	public int getContentLength() {
		return contentLength;
	}
	
	public DependencyGraph getDependencyGraph() {
		return this.dependencyGraph;
	}
	
	public List getSeedClassNameList() {
		return seedClassNameList;
	}

	private void addNode(ClassNode node, List classList) {
		if (addedClasses.get(node.getValue()) == null) {

			// Depth first recurse adding static dependencies first:
			for (ClassNode child : node.getStaticDependencies()) {
				addNode(child, classList);
			}

			if (addedClasses.get(node.getValue()) == null) {
				classList.add(node);
				addedClasses.put(node.getValue(), true);
			}

			// then add runtime dependencies
			for (ClassNode child : node.getRunTimeDependencies()) {
				addNode(child, classList);
			}
		}
	}

	public void writeScriptTags(OutputStream out, Config config)
			throws IOException {

		String basePathString = config.getProperty(Config.PROP_SCRIPT_TAG_BASE_PATH);

		for (ClassNode item : getClassList()) {
			File file = dependencyGraph.getClassFileSet().getFileFromClassname(
					item.getValue());

			Path filePath = Paths.get(file.getAbsolutePath());

			/*
			 * Fix path string because java sees /. or \, as a folder and adds a
			 * .. to the relative path.
			 */
			String absoluteBasePath = new File(basePathString)
					.getCanonicalPath();
			/* ****************************************************************************************** */
			Path basePath = Paths.get(absoluteBasePath);
			
			LOG.info("Base: " + absoluteBasePath + ", path: " + file.getAbsolutePath());
			
			out.write(("\n")
					.getBytes());
		}

	}
	
	public void write(OutputStream out) throws IOException {
		MessageDigest md5 = null;
		iterator = classList.listIterator();
		try {
			md5 = MessageDigest.getInstance("MD5");
		}
		catch (NoSuchAlgorithmException nsae) {
			throw new RuntimeException("Java doesn't have MD5 hashing for some reason. JSCL needs it to create a unique id of the content. Aborting.");
		}
		while (iterator.hasNext()) {
			currentNode = iterator.next();
			File file = classFileSet.getFileFromClassname(currentNode
					.getValue());
			out.write(("\n\n//File: " + file.getName() + "\n").getBytes());
			Bundler.copy(new FileInputStream(file), out, md5);
		}
		
		String md5String = new BigInteger(1, md5.digest()).toString(16);
		
		out.write(("\n\nvar JSCL_UNIQUE_BUNDLE_HASH=" + "'" + md5String + "';\n\n").getBytes());
	}

	private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;

	public static int copy(InputStream input, OutputStream output, MessageDigest md5)
			throws IOException {
		long count = copyLarge(input, output, md5);
		if (count > Integer.MAX_VALUE) {
			return -1;
		}
		return (int) count;
	}

	public static long copyLarge(InputStream input, OutputStream output, MessageDigest md5)
			throws IOException {
		byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
		long count = 0;
		int n = 0;
		while (-1 != (n = input.read(buffer))) {
			md5.update(buffer);
			output.write(buffer, 0, n);
			count += n;
		}
		return count;
	}

	private List generateSeedFileList(Config config) {
		List seedFileList = new ArrayList();

		String seedFileString = config.getProperty(Config.PROP_SEED_FILES);
		String basePath = config.getProperty(Config.PROP_BASE_FOLDER);

		com.esotericsoftware.wildcard.Paths paths;
		for (String path : seedFileString.split(",")) {
			paths = new com.esotericsoftware.wildcard.Paths();
			paths.glob(basePath, path);
			seedFileList.addAll(paths.getFiles());
		}

		return seedFileList;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy