Package flex2.compiler.as3

Source Code of flex2.compiler.as3.SignatureExtension

/*
*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*/

package flex2.compiler.as3;

import java.io.File;
import java.io.IOException;
import java.util.zip.Adler32;
import java.util.zip.Checksum;

import macromedia.asc.parser.Node;
import macromedia.asc.parser.PackageDefinitionNode;
import macromedia.asc.parser.ProgramNode;
import macromedia.asc.util.Context;
import flash.util.ExceptionUtil;
import flash.util.FileUtils;
import flex2.compiler.CompilationUnit;
import flex2.compiler.as3.reflect.NodeMagic;
import flex2.compiler.as3.reflect.TypeTable;
import flex2.compiler.common.CompilerConfiguration;
import flex2.compiler.util.MimeMappings;
import flex2.compiler.util.ThreadLocalToolkit;
import flex2.compiler.util.CompilerMessage.CompilerWarning;

/**
* Compiler extension to generate AS3 class/interface signatures.
*
* Singleton.
*
* Signatures will not be generated unless -incremental or -keep-generated-signatures are true.
*
* This even generates signatures for InMemoryFiles, etc.. Signatures may be emitted to the file
* system as .sig files. Like keep-generated-actionscript, this doesn't flush the directory of
* existing .sig files.
*
* Related compiler configurating settings:
*      compiler.keep-generated-signatures
*      compiler.signature-directory [default: generated-signatures]
*
* This class is NOT thread-safe. Not that this matters...
*     
* @author Jono Spiro
*/
public final class SignatureExtension implements Extension
{
    public final static boolean debug = true;

    public static final String DEFAULT_SIG_DIR   = "generated-signatures";
    public static final String WARNING_ATTRIBUTE = "SignatureExtension.warning";

    /**
     * Don't mess with this directly, please. Mess with it indirectly using init() :~)
     */
    public static String signatureDirectory;

    private static boolean keepGeneratedSignatures;
   
    /** singleton instance */
    private static SignatureExtension _instance;
   
    /** private since we're a singleton */
    private SignatureExtension() {}

    /**
     * Be sure that you init() the class before using it.
     */
    public static SignatureExtension getInstance()
    {
        if (_instance == null)
            _instance = new SignatureExtension();
           
        return _instance;
    }

    /**
     * Initializes the singleton; be sure you do this before using the extension.
     */
    public static void init(CompilerConfiguration compilerConfig)
    {
        assert compilerConfig != null;
       
        if (compilerConfig.getKeepGeneratedSignatures())
        {
            keepGeneratedSignatures = true;
            final String tmp = compilerConfig.getSignatureDirectory();
            signatureDirectory = ((tmp == null) ? DEFAULT_SIG_DIR : tmp);
        }
    }
   
    private static void setWarning(CompilationUnit unit, CompilerWarning warning)
    {
        unit.getContext().setAttribute(WARNING_ATTRIBUTE, warning);
    }
   
    private static CompilerWarning getWarning(CompilationUnit unit)
    {
        return (CompilerWarning) unit.getContext().getAttribute(WARNING_ATTRIBUTE);
    }
   
//    /**
//     * For external use (CompilerAPI.java) to generate a signature checksum on the fly,
//     * without emitting errors, updating the CompilationUnit, or saving the signature to a file.
//     */
//    public static Long getSignatureChecksum(final CompilationUnit unit)
//    {
//        final Long chksum = computeChecksum(unit, generateSignature(unit));
//       
//        // generateSignature might log a warning if the signature could not be generated
//        // since this method is supposed to be side-effectless.
//        if (chksum == null)
//            unit.getContext().setAttribute(WARNING_ATTRIBUTE, null);
//       
//        return chksum;
//    }
   
    // interface methods
    public void parse1  (CompilationUnit unit, TypeTable typeTable) { doSignatureGeneration(unit); }
    public void parse2  (CompilationUnit unit, TypeTable typeTable) {}
    public void analyze1(CompilationUnit unit, TypeTable typeTable) {}
    public void analyze2(CompilationUnit unit, TypeTable typeTable) {}
    public void analyze3(CompilationUnit unit, TypeTable typeTable) {}
    public void analyze4(CompilationUnit unit, TypeTable typeTable) {}
    public void generate(CompilationUnit unit, TypeTable typeTable)
    {
        // since warnings are common when a file is malformed, most unsuccessful compilations
        // will have some kind of signature warning... the only REAL warnings that are interesting
        // are those that occur on well-formed programs that compile. only output warnings if the
        // application was able to successfully compile.
       
        // ADDITIONALLY, we'll only even attempt to output warnings IF we got to code generation.
       
        // disabled for RTM since this has been active for a few betas and proven itself;
        // even if warnings occur, we default to safe behavior.
        //
        // no reason to harass our customers anymore ;-)
        if (debug)
        {
            final CompilerWarning warning = getWarning(unit);
            if((warning != null) && (ThreadLocalToolkit.errorCount() == 0))
            {
                ThreadLocalToolkit.log(warning);
            }
        }
    }
   
    private static void doSignatureGeneration(final CompilationUnit unit)
    {
        // debug("doSignatureGeneration(" + unit.getSource().getName() + ")");
       
        // generate the signature
        final String sigString = generateSignature(unit);

        // computer and store the checksum of the signature
        {
            final Long checksum = computeChecksum(unit, sigString);
           
            // make sure we've never parsed this unit before -- we don't want to waste passes
            //TODO concern: Source.copy() means that if you recompile a copied source, this
            //              assertion will explode. Unsure IF that can/should happen;
            //              unless CU.resetKeepTypeInfo() or CU.reset() clears the signature
            //              and is always called before recompiling a copied unit.
            // this should never, ever happen in production compiler -- and has never happened so far, to boot.
            // so I've upgraded it to an assertion, to be sure that we'd catch it during development.
            assert !unit.hasSignatureChecksum() : "overwriting an existing checksum for " + unit;
           
            unit.setSignatureChecksum(checksum);
        }
       
        // dump signature to filesystem
        // If the siggen failed, a file won't get created. I would LIKE to
        // write a file saying *** FAILED *** or some such, but if the package or class
        // name was one of the problems, then the generated file name is unreliable
        // (since it is based on the package name) and could overwrite an existing,
        // valid, signature file
        if ((sigString != null) && (signatureDirectory != null))
        {
            final ProgramNode           pNode    = (ProgramNode)unit.getSyntaxTree();
            final PackageDefinitionNode pdn      = pNode.pkgdefs.first();
            final String                pkgName  = NodeMagic.getPackageName(pdn).replace('.', '_');
            // final VirtualFile           vFile    = unit.getSource().getBackingFile();
           
            // this is only kinda sketchy, but it works... all I need is the file name, not the path
            final String fileName = new File(unit.getSource().getNameForReporting()).getName();
           
            // older sketchy method
            // URI uri;
            // try
            // {
                // apparently a URL is-a URI, therefore, this should never fail
                // except... some vFiles are in-memory, which give us a "memory://" URI, invalid
            //     uri      = new URI(vFile.getURL());
            //     fileName = new File(uri).getName();
            // }
            // catch(URISyntaxException e)
            // {
            //     fileName = new File(vFile.getName()).getName();
            // }
           
            final String srcName
                 = fileName.substring(0, (fileName.length() -
                                          MimeMappings.getExtension(unit.getSource().getMimeType()).length()));
           
            final String sigName = pkgName.concat(pkgName.equals("") ? "" : "_")
                                                  .concat(srcName)
                                                  .concat(".sig");
           
            try
            {
                //final String NL = SignatureEvaluator.NEWLINE;
                FileUtils.writeClassToFile(signatureDirectory, "", sigName,
                                           /* (("SOURCE: " + fileName + NL +
                                             "DIGEST: " + chksum   + NL +
                                             "-------------------" + NL + NL) + */
                                             sigString);
            }
            catch(IOException ioe)
            {
                final CompilerWarning warning = new KeepGeneratedSignatureFileWritingFailed(sigName);
                warning.setPath(unit.getSource().getNameForReporting());
                setWarning(unit, warning);
            }
        }
    }

    private static String generateSignature(final CompilationUnit unit)
    {
        final Context cx = unit.getContext().getAscContext();
       
        String sigString = null;
        {
            // good estimate of buffer size for a signature
            final int powerOfTwoBufferSize
                    = (int)Math.pow(2, Math.round(Math.log(unit.getSource().size())/Math.log(2)));

            // generate the signature
            final SignatureEvaluator evaluator =
                new SignatureEvaluator(powerOfTwoBufferSize, keepGeneratedSignatures);
            evaluator.setLocalizationManager(ThreadLocalToolkit.getLocalizationManager());
            ((ProgramNode)unit.getSyntaxTree()).evaluate(cx, evaluator);
            sigString = evaluator.getSignature();
        }
        return sigString;
    }

    private static Long computeChecksum(CompilationUnit unit, String sigString)
    {
        Long chksum = null;
       
        if(sigString != null)
        {
            //store the signature as a checksum
            final byte[] bytes = sigString.getBytes();
           
            final Checksum checksum = new Adler32(); // much faster than CRC32, almost as reliable
            checksum.update(bytes, 0, bytes.length);
            chksum = new Long(checksum.getValue());
           
           // debug("COMPUTE   CRC32: " + chksum + "\t--> " + unit.getSource().getNameForReporting());
        }
        return chksum;
    }
   
    public static class KeepGeneratedSignatureFileWritingFailed extends CompilerWarning
    {
        /** serialVersionUID */
        private static final long serialVersionUID = -2077778266808945113L;
    
        public String toFile;

        public KeepGeneratedSignatureFileWritingFailed(String toFile)
        {
            super();
            this.toFile = toFile;
        }
    }
}

TOP

Related Classes of flex2.compiler.as3.SignatureExtension

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.