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

com.dragome.compiler.writer.Assembly Maven / Gradle / Ivy

There is a newer version: 0.96-beta4
Show newest version
/*******************************************************************************
 * Copyright (c) 2011-2014 Fernando Petrola
 *
 * This file is part of Dragome SDK.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 ******************************************************************************/

// Copyright 2011 The j2js Authors. All Rights Reserved.
//
// This file is part of j2js.
//
// j2js is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// j2js 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with j2js. If not, see .

package com.dragome.compiler.writer;

import java.io.File;
import java.io.FileFilter;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.io.IOUtils;

import com.dragome.commons.compiler.classpath.ClasspathFile;
import com.dragome.commons.compiler.classpath.ClasspathFileFilter;
import com.dragome.compiler.DragomeJsCompiler;
import com.dragome.compiler.Project;
import com.dragome.compiler.generators.DragomeJavaScriptGenerator;
import com.dragome.compiler.generators.JavaScriptCompressor;
import com.dragome.compiler.type.Signature;
import com.dragome.compiler.units.ClassUnit;
import com.dragome.compiler.units.ConstructorUnit;
import com.dragome.compiler.units.MemberUnit;
import com.dragome.compiler.units.ProcedureUnit;
import com.dragome.compiler.utils.Log;

public class Assembly
{
	public List entryPoints= new ArrayList();
	private transient Log logger;
	private transient String entryPointClassName;
	private Project project;
	private Set taintedSignatures= new LinkedHashSet();
	private Set unprocessedTaintedSignatures= new LinkedHashSet();
	String[] patterns;
	private Collection resolvedTypes= new ArrayList();
	private transient File targetLocation;
	private ClasspathFileFilter classpathFilter;

	public Assembly()
	{
		//	patterns= Utils.getProperty("dragomeJs.taintIfInstantiated").split(";");
		//	for (int i= 0; i < patterns.length; i++)
		//	{
		//
		//	    String pattern= patterns[i].replaceAll("\\s", "");
		//	    pattern= pattern.replaceAll("\\.", "\\\\.");
		//	    pattern= pattern.replaceAll("\\*", ".*");
		//	    pattern= pattern.replaceAll("\\(", "\\\\(");
		//	    pattern= pattern.replaceAll("\\)", "\\\\)");
		//	    patterns[i]= pattern;
		//	}
	}

	private void pipeFileToStream(Writer writer, String relativeFilePath) throws IOException
	{
		ClasspathFile fileObject= DragomeJsCompiler.compiler.fileManager.getFileForInput(relativeFilePath);
		String content;
		if (DragomeJsCompiler.compiler.isCompression())
		{
			JavaScriptCompressor compressor= new JavaScriptCompressor();
			content= compressor.compress(fileObject.openInputStream());
		}
		else
		{
			content= IOUtils.toString(fileObject.openInputStream());
		}
		writer.write(content);

		fileObject.close();
	}

	private void removeOldAssemblies(File assembly)
	{
		final String numericPostfixPattern= "-[0-9]*$";
		final String prefix= assembly.getName().replaceAll(numericPostfixPattern, "");

		File[] oldAssemblies= assembly.getParentFile().listFiles(new FilenameFilter()
		{
			public boolean accept(File dir1, String name)
			{
				return name.matches(prefix + numericPostfixPattern);
			}
		});

		if (oldAssemblies == null)
		{
			return;
		}

		for (File oldAssemblyDir : oldAssemblies)
		{
			for (File file : oldAssemblyDir.listFiles())
			{
				file.delete();
			}
			oldAssemblyDir.delete();
		}
	}

	public int createAssembly() throws IOException
	{
		logger= Log.getLogger();
		logger.debug("Packing ...");

		removeOldAssemblies(targetLocation);

		String loaderName= DragomeJsCompiler.compiler.getTargetPlatform().toLowerCase();
		Writer writer;

		if ("javascript".equals(loaderName))
		{
			writer= new FileWriter(targetLocation);
			pipeFileToStream(writer, "dragome/javascript/loaders/" + loaderName + ".js");
		}
		else
		{
			targetLocation.mkdirs();
			writer= new JunkWriter(targetLocation);
		}
		//writer.write("// Assembly generated by dragomeJs " + Utils.getVersion() + " on " + Utils.currentTimeStamp() + "\n");

		writer.write("//***********************************************************************\n");
		writer.write("//* Generated with Dragome SDK Copyright (c) 2011-2016 Fernando Petrola *\n");
		writer.write("//***********************************************************************\n");
		writer.write("\n");

		//	pipeFileToStream(writer, "javascript/q-3.0.js");

		pipeFileToStream(writer, "dragome/javascript/runtime.js");
		//	writer.write("dragomeJs.assemblyVersion = 'dragomeJs Assembly " + targetLocation.getName() + "@" + Utils.currentTimeStamp() + "';\n");

		writer.write("dragomeJs.userData = {};\n");

		//	int classCount= 0;
		//	for (ClassUnit fileUnit : project.getClasses())
		//	{
		//	    if (!fileUnit.isTainted())
		//		continue;
		//	    writer.write("dragomeJs.");
		//	    writer.write(DECLARECLASS);
		//	    writer.write("(\"" + fileUnit.getSignature() + "\"");
		//	    writer.write(", " + fileUnit.getSignature().getId());
		//	    writer.write(");\n");
		//	    classCount++;
		//	}

		project.currentGeneratedMethods= 0;

		if (DragomeJsCompiler.compiler.getSingleEntryPoint() != null)
		{
			Signature signature= project.getSignature(DragomeJsCompiler.compiler.getSingleEntryPoint());
			ClassUnit clazz= project.getClassUnit(signature.className());
			clazz.write(0, writer);
		}
		else
		{
			ClassUnit object= project.getJavaLangObject();
			object.write(0, writer);

			do
			{
				ClassUnit.oneWritten= false;
				for (ClassUnit cu : project.getClasses())
				{
					//		if (cu.isInterface)
					{
						cu.write(0, writer);
					}
				}
			}
			while (ClassUnit.oneWritten);

		}

		ClassUnit stringClazz= project.getClassUnit(String.class.getName());
		ClassUnit stringSuperClazz= stringClazz.getSuperUnit();

		Collection declaredMembers= new ArrayList(stringClazz.getDeclaredMembers());
		declaredMembers.addAll(stringSuperClazz.getDeclaredMembers());

		for (MemberUnit memberUnit : declaredMembers)
		{
			Signature signature= memberUnit.getSignature();
			String normalizeExpression= DragomeJavaScriptGenerator.normalizeExpression(signature);
			writer.write("String.prototype." + normalizeExpression + "= java_lang_String.prototype." + normalizeExpression + ";\n");
		}

		writer.write("String.prototype.classname= \"java_lang_String\";\n");

		for (MemberUnit member : ClassUnit.stringInits)
		{
			String memberData= member.getData();
			member.setData(member.getData().substring(1));
			member.write(1, writer);
			member.setData(memberData);
			if (member instanceof ProcedureUnit)
			{
				project.currentGeneratedMethods++;
				writer.flush();
			}
		}

		//	project.writeClinits(writer);

		if (getProject().getOrCreateClassUnit("java.lang.String").isTainted())
		{
			writer.write("String.prototype.clazz = java_lang_String;\n");
		}

		//	writer.write("dragomeJs.onLoad('" + entryPointClassName + "#main(java.lang.String[])void');\n");

		writer.write("javascript_Utils.$init$void();\n");

		project.writeSignatures(writer);

		writer.write("java_lang_Object.prototype.toString= function (){return this.$toString$java_lang_String();};\n"); //TODO mover despues de creacion de Object

		//		writer.write("Array.prototype.$clone$java_lang_Object= java_lang_Object.prototype.$clone$java_lang_Object;\n"); //TODO mover despues de creacion de Object

		writeAnnotationsInsertion(writer);

		//	writer.write("new " + mainClass + "();\n");
		//	writer.write(mainClass + "." + mainMethod + "();\n");

		writer.write("onReady(function(){setupCheckCast(); _ed.executeMainClass();});");

		writer.close();

		return project.currentGeneratedMethods;
	}

	private void writeAnnotationsInsertion(Writer writer) throws IOException
	{
		Set typeDeclarations= getProject().getTypeDeclarationsWithAnnotations();

		for (String typeDeclaration : typeDeclarations)
		{
			String[] key= typeDeclaration.split("#");
			if (!"::::bytes".equals(key[2])) //TODO fixme: scala annotations
				writer.write(String.format("dragomeJs.addTypeAnnotation(\"%s\", \"%s\", \"%s\", \"%s\");\n", key[0], key[1], key[2], key[3].trim()));
		}
	}

	public void processTainted()
	{
		while (unprocessedTaintedSignatures.size() > 0)
		{
			processSingle(popSignature());
			if (unprocessedTaintedSignatures.size() == 0)
			{
				processOverWrittenMembers();
			}
		}
	}

	public void processSingle(Signature signature)
	{
		ClassUnit clazz= resolve(signature.className());
		File file= new File(signature.className().replace(".", "/"));
		if (classpathFilter.accept(file, file))
		{
			String methodPart= signature.relativeSignature();
			boolean found= false;
			for (MemberUnit member : clazz.getMembers(methodPart))
			{
				taint(member);
				found= true;
			}

			if (!found)
			{
				Log.getLogger().debug("No such method: " + signature);
				//			throw new RuntimeException("No such method: " + signature);
			}
		}
	}

	private ClassUnit resolve(String className)
	{
		ClassUnit clazz= project.getOrCreateClassUnit(className);

		if (className.startsWith("["))
		{
			project.resolve(clazz);
		}
		else
		{
			project.resolve(clazz);
			taint(className + "#()void");
		}

		resolvedTypes.add(clazz);

		return clazz;
	}

	public ClassUnit resolveNoTainting(String className)
	{
		ClassUnit clazz= project.getOrCreateClassUnit(className);

		if (className.startsWith("["))
		{
			project.resolve(clazz);
		}
		else
		{
			project.resolve(clazz);
		}

		resolvedTypes.add(clazz);

		return clazz;
	}

	private void taintImplicitelyAccessedMembers(ClassUnit clazz)
	{

		for (MemberUnit member : clazz.getDeclaredMembers())
		{
			//	    for (int i= 0; i < patterns.length; i++)
			{
				//		if (member.getAbsoluteSignature().toString().matches(patterns[i]))
				{
					taint(member.getAbsoluteSignature());
				}
			}
		}
	}

	private void taintIfSuperTainted(ClassUnit clazz)
	{
		if (clazz.getName().equals("java.lang.Object"))
			return;

		for (MemberUnit member : clazz.getDeclaredMembers())
		{
			for (ClassUnit superType : clazz.getSupertypes())
			{
				Signature signature= Project.getSingleton().getSignature(superType.getName(), member.getSignature().toString());
				//if (taintedSignatures.contains(signature))
				{
					taint(member);
				}
			}
		}
	}

	private void taintTargetSignatures(ProcedureUnit method)
	{
		for (Signature targetSignature : method.getTargetSignatures())
		{
			taint(targetSignature);
		}
	}

	private void processOverWrittenMembers()
	{
		Iterator classIterator= resolvedTypes.iterator();
		while (classIterator.hasNext())
		{
			ClassUnit clazz= classIterator.next();
			if (clazz.isConstructorTainted)
				taintIfSuperTainted(clazz);
			;
		}
	}

	public void taint(String signature)
	{
		signature= signature.replaceAll("\\s", "");

		Signature s= Project.getSingleton().getSignature(signature);
		if (s.isClass())
		{
			ClassUnit clazz= resolve(s.className());

			for (MemberUnit member : clazz.getDeclaredMembers())
			{
				taint(member.getAbsoluteSignature());
			}
		}
		else
		{
			taint(s);
		}

	}

	private Signature popSignature()
	{
		Iterator iter= unprocessedTaintedSignatures.iterator();
		Signature signature= iter.next();
		iter.remove();
		return signature;
	}

	public void taint(Signature signature)
	{
		if (!signature.toString().contains("#"))
		{
			throw new IllegalArgumentException("Signature must be field or method: " + signature);
		}

		if (taintedSignatures.contains(signature))
			return;

		taintedSignatures.add(signature);
		unprocessedTaintedSignatures.add(signature);
	}

	public void taint(MemberUnit member)
	{
		member.setTainted();

		member.getDeclaringClass().setSuperTainted();
		if (member instanceof ProcedureUnit)
		{
			taintTargetSignatures((ProcedureUnit) member);
			if (member instanceof ConstructorUnit)
			{
				member.getDeclaringClass().isConstructorTainted= true;
				taintImplicitelyAccessedMembers(member.getDeclaringClass());
			}
		}
	}

	public void setProject(Project project)
	{
		this.project= project;
	}

	public Project getProject()
	{
		return project;
	}

	public String getEntryPointClassName()
	{
		return entryPointClassName;
	}

	public Assembly setEntryPointClassName(String entryPointClassName)
	{
		this.entryPointClassName= entryPointClassName;
		return this;
	}

	public File getTargetLocation()
	{
		return targetLocation;
	}

	public void setTargetLocation(File targetLocation)
	{
		this.targetLocation= targetLocation;
	}

	public void addEntryPoint(String memberSignature)
	{
		entryPoints.add(memberSignature);
	}

	public void setClasspathFilter(ClasspathFileFilter classpathFilter)
	{
		this.classpathFilter= classpathFilter;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy