Package net.rim.tumbler

Source Code of net.rim.tumbler.WidgetPackager

/*
* Copyright 2010-2011 Research In Motion Limited.
*
* Licensed 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 net.rim.tumbler;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import net.rim.tumbler.airpackager.AirPackager;
import net.rim.tumbler.config.WidgetAccess;
import net.rim.tumbler.config.WidgetConfig;
import net.rim.tumbler.config.WidgetFeature;
import net.rim.tumbler.exception.CommandLineException;
import net.rim.tumbler.exception.PackageException;
import net.rim.tumbler.exception.ValidationException;
import net.rim.tumbler.extension.ExtensionMap;
import net.rim.tumbler.file.FileManager;
import net.rim.tumbler.log.LogType;
import net.rim.tumbler.log.Logger;
import net.rim.tumbler.mxmlc.Mxmlc;
import net.rim.tumbler.serialize.WidgetConfigSerializer;
import net.rim.tumbler.serialize.WidgetConfig_v1Serializer;
import net.rim.tumbler.session.BBWPProperties;
import net.rim.tumbler.session.SessionManager;
import net.rim.tumbler.signing.SigningSupport;
import net.rim.tumbler.xml.ConfigXMLParser;
import net.rim.tumbler.xml.XMLParser;

public class WidgetPackager {
   
   
    private static final String[] STANDARD_OUTPUTS = new String[] { ".cod",
            ".alx", ".cso", ".csl" };
    private static final String[] OTA_OUTPUTS = new String[] { ".cod", ".jad" };

    // TODO: retrieve from logger
    public static final String BLACKBERRY_WIDGET_PORTAL_URL = "http://www.blackberry.com/developers/widget/";
    public static final String PROPERTIES_FILE = "bbwp.properties";
    public static final String SIGNATURE_KEY_FILE = "sigtool.csk";

    private static final String AUTOGEN_FILE = "webworks/config/CustomData.as";
   
    private static final int NO_ERROR_RETURN_CODE = 0;
    private static final int PACKAGE_ERROR_RCODE = 1;
    private static final int VALIDATION_ERROR_RCODE = 2;
    private static final int RUNTIME_ERROR_RCODE = 3;
    private static final int UNEXPECTED_ERROR_RCODE = 4;
    private static final int COMMAND_LINE_EXCEPTION = 5;

    /**
     * Enables signing.
     */
    private static final boolean ENABLE_SIGNING = true;
   
    public static void main(String[] args) {
        WidgetPackager wp = new WidgetPackager();
        wp.go(args);
    }
   
    public void go(String[] args) {
        int returnCode = NO_ERROR_RETURN_CODE;
       
        try {
            CmdLineHandler cmd = new CmdLineHandler();
            if (!cmd.parse(args)) {
                // nothing to package
                System.exit(NO_ERROR_RETURN_CODE);
            }
           
            // create SessionManager
            SessionManager sessionManager = cmd.createSession();

            // create bbwp.properties
            Logger.logMessage(LogType.INFO, "PROGRESS_SESSION_BBWP_PROPERTIES");
            String propertiesFile = sessionManager.getBBWPJarFolder() + WidgetPackager.PROPERTIES_FILE;
            BBWPProperties bbwpProperties = new BBWPProperties(propertiesFile, sessionManager.getSessionHome());

            // validate widget archive
            Logger.logMessage(LogType.INFO, "PROGRESS_VALIDATING_WIDGET_ARCHIVE");
            WidgetArchive wa = new WidgetArchive(sessionManager.getWidgetArchive());
            wa.validate();

            // parse/validate config.xml
            Logger.logMessage(LogType.INFO, "PROGRESS_SESSION_CONFIGXML");
            XMLParser xmlparser = new ConfigXMLParser();     
            WidgetConfig config = xmlparser.parseXML(wa); // raw data, without \
           
            // create/clean outputs/source
            // Logger.printInfoMessage("Widget packaging starts...");
            FileManager fileManager = new FileManager(bbwpProperties);
            Logger.logMessage(LogType.INFO, "PROGRESS_FILE_POPULATING_SOURCE");
            fileManager.prepare();

            //
            // Copy the JS extensions.
            //
            Map<String, Vector<String>> entryClassTable = null;
            if (SessionManager.getInstance().isPlayBook()) {
                entryClassTable = copyExtensions(bbwpProperties, config);
            }

            // Set 3rd party extension classes
            if (!SessionManager.getInstance().isPlayBook()) {
                config.setExtensionClasses(fileManager.getExtensionClasses());
            }
           
            // create autogen file
            WidgetConfigSerializer wcs = new WidgetConfig_v1Serializer(config, entryClassTable);
            byte[] autogenFile = wcs.serialize();
            fileManager.writeToSource(autogenFile, AUTOGEN_FILE);

            // create jdw/jdp files
            if (!SessionManager.getInstance().isPlayBook()) {
            fileManager.generateProjectFiles(sessionManager.getSourceFolder(),
                    sessionManager.getArchiveName(), config.getName(), config
                            .getVersion(), config.getAuthor(),config.getContent(),config.getBackgroundSource(),config.isStartupEnabled(), config
                            .getIconSrc(), config.getHoverIconSrc(),
                    fileManager.getFiles(), bbwpProperties.getImports());
            }

            // run mxmlc to compile ActionScript into SWF
            Logger.logMessage(LogType.INFO, "PROGRESS_COMPILING");
            if (SessionManager.getInstance().isPlayBook()) {
                Mxmlc mxmlc = new Mxmlc(bbwpProperties, config);

                // just for demo purposes, we hard code the source file path
                mxmlc.run();
           
                // *** just for demo purposes, we HARD CODE THE SOURCE PATH ***
                Logger.logMessage(LogType.INFO, "PROGRESS_PACKAGING");
                AirPackager packager = new AirPackager(bbwpProperties, config);
                int ret = packager.run();
                if (ret==0)
                {
                  Logger.logMessage(LogType.INFO, "PACKAGING_COMPLETE");
                }
                else
                {
                  System.exit(ret);
                }
            }

            // generate ALX
            if (!SessionManager.getInstance().isPlayBook()) {
                generateAlxFile(config);
            }

            // Sign the cod if required
            if (ENABLE_SIGNING && sessionManager.requireSigning()) {
                Logger.logMessage(LogType.INFO, "PROGRESS_SIGNING");
                if (SessionManager.getInstance().isPlayBook()) {
                    try {
                        SigningSupport.signBar(bbwpProperties);
                    } catch (Exception e) {
                        File barFile = new File(sessionManager.getOutputFilepath());
                        if (barFile.isFile()) {
                            barFile.delete();
                        }
                        throw e;
                    }
                } else {
                    signCod(sessionManager);
                }
                Logger.logMessage(LogType.INFO, "PROGRESS_SIGNING_COMPLETE");
            }

            // clean/prep output folders
            fileManager.cleanOutput();

            // copy output files
            if (!SessionManager.getInstance().isPlayBook()) {
                Logger.logMessage(LogType.INFO, "PROGRESS_GEN_OUTPUT");
                fileManager.copyOutputsFromSource(STANDARD_OUTPUTS, OTA_OUTPUTS);
            }

            // clean source (if necessary)
            if (!sessionManager.requireSource()) {
                fileManager.cleanSource();
            }

            Logger.logMessage(LogType.INFO, "PROGRESS_COMPLETE");
        } catch (CommandLineException cle) {
                        Logger.logMessage(LogType.ERROR, cle.getMessage(), cle.getInfo());
                        Logger.logMessage(LogType.NONE, CmdLineHandler.isPlayBook() ? "BBWP_PLAYBOOK_USAGE" : "BBWP_USAGE", getVersion());
                        returnCode = COMMAND_LINE_EXCEPTION;
        } catch (PackageException pe) {
            Logger.logMessage(LogType.ERROR, pe.getMessage(), pe.getInfo());
            returnCode = PACKAGE_ERROR_RCODE;
        } catch (ValidationException ve) {
            Logger.logMessage(LogType.ERROR, ve.getMessage(), ve.getInfo());
            returnCode = VALIDATION_ERROR_RCODE;
        } catch (RuntimeException re) {
            Logger.logMessage(LogType.FATAL, re);
            returnCode = RUNTIME_ERROR_RCODE;
        } catch (Exception e) {
            System.out.println(e);
            returnCode = UNEXPECTED_ERROR_RCODE;
        }
       
        System.exit(returnCode);
    }
   
        public static Object[] getVersion() {
            return new Object[] { new WidgetPackager().getClass().getPackage().getImplementationVersion() };
        }
       

    private static void signCod(SessionManager sessionManager) throws Exception {
        Process signingProcess;
        long lastModified = 0;
        String codFullname = sessionManager.getSourceFolder()
                + File.separator
                + sessionManager.getArchiveName() + ".cod";

        try {
            lastModified = (new File(codFullname)).lastModified();
            String password = sessionManager.getPassword();
            File cwd = new File(sessionManager.getBBWPJarFolder());
            String cmdline = "java -jar SignatureTool.jar -a -c "
                    + (password.length() == 0 ? "" : "-p " + password + " ")
                    + "\"" + sessionManager.getSourceFolder()
                    + File.separator
                    + sessionManager.getArchiveName() + ".cod" + "\"";
            signingProcess = Runtime.getRuntime().exec(cmdline, null, cwd);
        } catch (IOException ex) {
            throw ex;
        }

        try {
            int signingResult = signingProcess.waitFor();

            // Check whether signing is successful
            if (signingResult != 0) {
                throw new PackageException("EXCEPTION_SIGNING_FAILED");
            }

            long newModified = (new File(codFullname)).lastModified();
            if (newModified == lastModified) {
                throw new PackageException("EXCEPTION_SIGNING_FAILED");
            }
        } catch (InterruptedException e) {
            throw e;
        }
    }

    // Generate a .alx file
    private static void generateAlxFile(WidgetConfig widgetConfig)
            throws IOException {
        String EOL = System.getProperty("line.separator");
        String fileName = SessionManager.getInstance().getSourceFolder()
                + File.separator
                + SessionManager.getInstance().getArchiveName() + ".alx";
        BufferedWriter writer = new BufferedWriter(new FileWriter(fileName));
        writer.write("<loader version=\"1.0\" >" + EOL);
        writer.write("<application id=\""
                + SessionManager.getInstance().getArchiveName() + "\">" + EOL);
        writer.write("<name>" + widgetConfig.getName() + "</name>" + EOL);
        if (widgetConfig.getDescription() != null) {
            writer.write("<description>" + widgetConfig.getDescription()
                    + "</description>" + EOL);
        }
        writer.write("<version>" + widgetConfig.getVersion() + "</version>"
                + EOL);
        if (widgetConfig.getAuthor() != null) {
            writer.write("<vendor>" + widgetConfig.getAuthor() + "</vendor>"
                    + EOL);
        }
        if (widgetConfig.getCopyright() != null) {
            writer.write("<copyright>" + widgetConfig.getCopyright()
                    + "</copyright>" + EOL);
        }
        writer.write("<fileset Java=\"1.45\">" + EOL);
        writer.write("<directory>");
        writer.write("</directory>" + EOL);
        writer.write("<files>");
        writer.write(SessionManager.getInstance().getArchiveName() + ".cod");
        writer.write("</files>" + EOL);
        writer.write("</fileset>" + EOL);
        writer.write("</application>" + EOL);
        writer.write("</loader>" + EOL);
        writer.close();
    }

    /**
     * Copies the correct set of extension source files from the extension
     * repository into the project area so that they can be compiled along
     * with the framework, and returns a hashtable populated with javascript
     * file names for use downstream. Each key in the hashtable is the
     * entry class name, and the value contains the relative pathnames
     * of the corresponding javascript files.
     *
     * @param bbwpProperties the current widget properties.
     * @param config the current widget configuration.
     *
     * @return a newly-created, populated hashtable as described above.
     */
    private static Map<String, Vector<String>> copyExtensions(
        BBWPProperties bbwpProperties,
        WidgetConfig config)
        throws IOException, PackageException
    {
        Map<String, Vector<String>> result = new LinkedHashMap<String, Vector<String>>();

        //
        // We need to copy the correct set of extension source files from the
        // extension repository into the project area so that they can be
        // compiled along with the framework.
        // The correct set of extension source files is determined using
        // the features identified in config.xml and the supported feature
        // set of each library.xml.
        //
        Hashtable<WidgetAccess, Vector<WidgetFeature>> accessTable = config.getAccessTable();
        // if the access table is empty, don't even bother since there's no features to search for
        if (accessTable.size() > 0) {
            //
            // Go ahead and traverse the extension repository, looking for
            // library.xml files to parse. This is independent of config.xml, so far.
            //

            ExtensionMap extensionMap = new ExtensionMap(
                "AIR",
                "default",
                bbwpProperties.getExtensionRepo(SessionManager.getInstance().getSessionHome())); // location of the extension repository

            //
            // Extract the set of feature IDs from the access table.
            // We flatten the structure since we don't care about the
            // access node or whether it applies to local access; all
            // we want are the unique feature IDs.
            //
            Set<String> featureIDs = new HashSet<String>();
            for (Vector<WidgetFeature> accessTableValue : accessTable.values()) {
                for (WidgetFeature widgetFeature : accessTableValue) {
                    featureIDs.add(widgetFeature.getID());
                }
            }

            //
            // For each feature ID in the set, we now perform the copying
            // based on the extension map that we constructed from the
            // library.xml files. The extension map will make sure we don't
            // copy the same set of files twice.
            //

            for (String featureID : featureIDs) {
                //
                // The ExtensionMap is responsible for avoiding duplication.
                // In particular, extension sets are marked as such after
                // they have been copied to avoid duplication.
                //
                // This method is also responsible for distinguishing between
                // ActionScript and JavaScript source files. For this purpose
                // file name extensions may be used.
                //
                extensionMap.copyRequiredFiles(
                    SessionManager.getInstance().getSourceFolder(), // destination for extensions
                    featureID);
            }
           
            //
            // Fill-in the javascript entry-class table. This is used elsewhere.
            //
            extensionMap.getCopiedFiles(".js", result, "WebWorksApplicationSharedJsRepository0" + File.separator);
        }
        return result;
    }
}
TOP

Related Classes of net.rim.tumbler.WidgetPackager

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.