Package com.dragome.compiler.writer

Source Code of com.dragome.compiler.writer.Assembly

/*******************************************************************************
* 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(){_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("#");
      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;
  }

}
TOP

Related Classes of com.dragome.compiler.writer.Assembly

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.