com.dragome.compiler.writer.Assembly.java Source code

Java tutorial

Introduction

Here is the source code for com.dragome.compiler.writer.Assembly.java

Source

/*******************************************************************************
 * 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 <http://www.gnu.org/licenses/>.

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.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.FileObject;
import com.dragome.compiler.utils.Log;

public class Assembly {
    public List<String> entryPoints = new ArrayList<String>();
    private transient Log logger;
    private transient String entryPointClassName;
    private Project project;
    private Set<Signature> taintedSignatures = new LinkedHashSet<Signature>();
    private Set<Signature> unprocessedTaintedSignatures = new LinkedHashSet<Signature>();
    String[] patterns;
    private Collection<ClassUnit> resolvedTypes = new ArrayList<ClassUnit>();
    private transient File targetLocation;
    private FileFilter 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 {
        FileObject 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-2014 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<MemberUnit> declaredMembers = new ArrayList<MemberUnit>(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("$(function(){setupCheckCast(); _ed.executeMainClass();});");

        writer.close();

        return project.currentGeneratedMethods;
    }

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

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

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

    public void processSingle(Signature signature) {
        ClassUnit clazz = resolve(signature.className());
        if (classpathFilter.accept(new File(signature.className().replace(".", "/")))) {
            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 + "#<clinit>()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<ClassUnit> 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<Signature> 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(FileFilter classpathFilter) {
        this.classpathFilter = classpathFilter;
    }

}