Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

adjustments to the packager code

  • Loading branch information...
commit 948c0e16016d50e9045f42aa8f75fa7bb3b4328e 1 parent 3ce2a18
Peter Wu authored
Showing with 2,608 additions and 665 deletions.
  1. +15 −0 packager/src/TumblerLauncher/TumblerLauncher.cpp
  2. +21 −6 packager/src/net/rim/tumbler/CmdLineHandler.java
  3. +20 −5 packager/src/net/rim/tumbler/WidgetArchive.java
  4. +29 −31 packager/src/net/rim/tumbler/WidgetPackager.java
  5. +745 −0 packager/src/net/rim/tumbler/config/FeatureManager.java
  6. +17 −2 packager/src/net/rim/tumbler/config/WidgetAccess.java
  7. +27 −9 packager/src/net/rim/tumbler/config/WidgetConfig.java
  8. +32 −0 packager/src/net/rim/tumbler/config/WidgetFeature.java
  9. +15 −0 packager/src/net/rim/tumbler/exception/CommandLineException.java
  10. +18 −1 packager/src/net/rim/tumbler/exception/PackageException.java
  11. +15 −0 packager/src/net/rim/tumbler/exception/SessionException.java
  12. +18 −1 packager/src/net/rim/tumbler/exception/ValidationException.java
  13. +108 −0 packager/src/net/rim/tumbler/file/ExtensionDependencyManager.java
  14. +315 −301 packager/src/net/rim/tumbler/file/FileManager.java
  15. +349 −0 packager/src/net/rim/tumbler/file/Library.java
  16. +15 −0 packager/src/net/rim/tumbler/file/TemplateFile.java
  17. +22 −1 packager/src/net/rim/tumbler/file/TemplateWrapper.java
  18. +15 −0 packager/src/net/rim/tumbler/log/LogType.java
  19. +23 −6 packager/src/net/rim/tumbler/log/Logger.java
  20. +20 −2 packager/src/net/rim/tumbler/log/resources/MessageBundle_en_CA.properties
  21. +96 −72 packager/src/net/rim/tumbler/rapc/Rapc.java
  22. +15 −0 packager/src/net/rim/tumbler/serialize/WidgetConfigSerializer.java
  23. +163 −145 packager/src/net/rim/tumbler/serialize/WidgetConfig_v1Serializer.java
  24. +46 −8 packager/src/net/rim/tumbler/session/BBWPProperties.java
  25. +14 −10 packager/src/net/rim/tumbler/session/SessionManager.java
  26. +65 −65 packager/src/net/rim/tumbler/xml/ConfigXMLParser.java
  27. +355 −0 packager/src/net/rim/tumbler/xml/LibraryXMLParser.java
  28. +15 −0 packager/src/net/rim/tumbler/xml/XMLParser.java
View
15 packager/src/TumblerLauncher/TumblerLauncher.cpp
@@ -1,3 +1,18 @@
+/*
+* 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.
+*/
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
View
27 packager/src/net/rim/tumbler/CmdLineHandler.java
@@ -1,3 +1,18 @@
+/*
+* 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.File;
@@ -31,24 +46,24 @@
private String _archiveName;
public boolean parse (String[] inputParams) throws PackageException, CommandLineException {
- // validate at least one parameter
+ // Validate at least one parameter.
if (inputParams.length < 1) {
throw new CommandLineException("EXCEPTION_INVALID_COMMAND_LINE");
}
- // get first param - exception case: /h
+ // Get first param - exception case: /h
String input1 = inputParams[0].toLowerCase().trim();
if (input1.equals(OPTION_HELP)) {
Logger.logMessage(LogType.NONE, "BBWP_USAGE", WidgetPackager.getVersion());
return false;
}
- // check archive format
+ // Check archive format
if (!input1.endsWith(".zip")) {
throw new CommandLineException("EXCEPTION_INVALID_COMMAND_LINE");
}
- // parse the command line
+ // Parse the command line
_widgetArchive = getAbsolutePath(input1);
_archiveName = parseWidgetName(_widgetArchive);
@@ -57,7 +72,7 @@ public boolean parse (String[] inputParams) throws PackageException, CommandLine
throw new PackageException("EXCEPTION_INVALID_ARCHIVE_NAME");
}
- // parse options
+ // Parse options
try {
parseOptionParameters(inputParams);
} catch (Exception e) {
@@ -67,7 +82,7 @@ public boolean parse (String[] inputParams) throws PackageException, CommandLine
}
public SessionManager createSession() throws Exception {
- // parse location of packager
+ // Parse location of packager
String bbwpInstallFolder;
String installPath = getAbsolutePath(SessionManager.BBWP_JAR_PATH);
File p = new File(installPath);
View
25 packager/src/net/rim/tumbler/WidgetArchive.java
@@ -1,3 +1,18 @@
+/*
+* 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.BufferedInputStream;
@@ -41,7 +56,7 @@ public void validate() throws ValidationException, PackageException {
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(
checksum));
- // parse each zip file
+ // Parse each zip file
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
String entryName = entry.getName().replace('\\', '/');
@@ -65,16 +80,16 @@ else if (_iconFile == null && entryName.equals("icon.gif")) {
_iconFile = "icon.gif";
}
else if (entry.isDirectory()) {
- // check for reservedDirs
+ // Check for reservedDirs
for (String reserved : RESERVED_DIRS) {
- // the dir entry name has a trailing / like "dir/"
+ // The dir entry name has a trailing / like "dir/"
if (entryName.equals(reserved + "/")) {
throw new ValidationException("EXCEPTION_ARCHIVE_RESERVED_DIR");
}
}
}
// Validate the resource name
- Pattern patternEntryName = Pattern.compile("[a-zA-Z0-9][a-zA-Z_0-9\\.]*");;
+ Pattern patternEntryName = Pattern.compile("[a-zA-Z-_0-9][a-zA-Z-_0-9\\.]*");;
String entity;
String fullEntryName = entryName;
boolean noMoreEntity = false;
@@ -103,7 +118,7 @@ else if (entry.isDirectory()) {
}
}
catch (FileNotFoundException fnfe) {
- // already validated for existence of archive file - never get here
+ // Already validated for existence of archive file - never get here
Logger.logMessage(LogType.FATAL, "EXCEPTION_WIDGET_ARCHIVE_NOT_FOUND");
}
catch (IOException ioe) {
View
60 packager/src/net/rim/tumbler/WidgetPackager.java
@@ -1,5 +1,5 @@
/*
-* Copyright 2010 Research In Motion Limited.
+* 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.
@@ -19,8 +19,6 @@
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
import net.rim.tumbler.config.WidgetConfig;
import net.rim.tumbler.exception.CommandLineException;
@@ -39,31 +37,31 @@
public class WidgetPackager {
-
public static final String[] STANDARD_OUTPUTS = new String[] { ".cod",
".alx", ".cso", ".csl" };
public 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/webworkssdk/";
- public static final String PROPERTIES_FILE = "bbwp.properties";
- public static final String SIGNATURE_KEY_FILE = "sigtool.csk";
+ // TODO: retrieve from logger
+ public static final String BLACKBERRY_WIDGET_PORTAL_URL = "http://www.blackberry.com/developers/webworkssdk/";
+ public static final String PROPERTIES_FILE = "bbwp.properties";
+ public static final String SIGNATURE_KEY_FILE = "sigtool.csk";
- private static final String AUTOGEN_FILE = "blackberry/web/widget/autogen/WidgetConfigAutoGen.java";
-
- 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;
+ private static final String AUTOGEN_FILE = "blackberry/web/widget/autogen/WidgetConfigAutoGen.java";
+
+ 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;
public static void main(String[] args) {
WidgetPackager wp = new WidgetPackager();
- wp.go(args);
+ int returnCode = wp.go(args);
+ System.exit(returnCode);
@filmaj
filmaj added a note

Yes, exit codes from the packager! Thank you! :beer:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
}
- public void go(String[] args) {
+ public int go(String[] args) {
Logger.logMessage(LogType.INFO, "PROGRESS_CMDLINE_OPTIONS");
int returnCode = NO_ERROR_RETURN_CODE;
@@ -71,7 +69,7 @@ public void go(String[] args) {
CmdLineHandler cmd = new CmdLineHandler();
if (!cmd.parse(args)) {
// nothing to package
- System.exit(NO_ERROR_RETURN_CODE);
+ return NO_ERROR_RETURN_CODE;
}
// create SessionManager
@@ -99,7 +97,7 @@ public void go(String[] args) {
// create/clean outputs/source
// Logger.printInfoMessage("BlackBerry WebWorks application packaging starts...");
- FileManager fileManager = new FileManager(bbwpProperties);
+ FileManager fileManager = new FileManager(bbwpProperties, config.getAccessTable());
Logger.logMessage(LogType.INFO, "PROGRESS_FILE_POPULATING_SOURCE");
fileManager.prepare();
@@ -120,7 +118,7 @@ public void go(String[] args) {
// run rapc
Logger.logMessage(LogType.INFO, "PROGRESS_COMPILING");
- Rapc rapc = new Rapc(bbwpProperties, config);
+ Rapc rapc = new Rapc(bbwpProperties, config, fileManager.getCompiledJARDependencies());
if (!rapc.run(fileManager.getFiles())) {
throw new PackageException("EXCEPTION_RAPC");
}
@@ -149,9 +147,9 @@ public void go(String[] args) {
Logger.logMessage(LogType.INFO, "PROGRESS_COMPLETE");
} catch (CommandLineException cle) {
- Logger.logMessage(LogType.ERROR, cle.getMessage(), cle.getInfo());
- Logger.logMessage(LogType.NONE, "BBWP_USAGE", getVersion());
- returnCode = COMMAND_LINE_EXCEPTION;
+ Logger.logMessage(LogType.ERROR, cle.getMessage(), cle.getInfo());
+ Logger.logMessage(LogType.NONE, "BBWP_USAGE", getVersion());
+ returnCode = COMMAND_LINE_EXCEPTION;
} catch (PackageException pe) {
Logger.logMessage(LogType.ERROR, pe.getMessage(), pe.getInfo());
returnCode = PACKAGE_ERROR_RCODE;
@@ -162,17 +160,16 @@ public void go(String[] args) {
Logger.logMessage(LogType.FATAL, re);
returnCode = RUNTIME_ERROR_RCODE;
} catch (Exception e) {
- System.out.println(e);
+ Logger.logMessage(LogType.ERROR, e);
returnCode = UNEXPECTED_ERROR_RCODE;
}
- System.exit(returnCode);
+ return returnCode;
+ }
+
+ public static Object[] getVersion() {
+ return new Object[] { new WidgetPackager().getClass().getPackage().getImplementationVersion() };
}
-
- public static Object[] getVersion() {
- return new Object[] { new WidgetPackager().getClass().getPackage().getImplementationVersion() };
- }
-
private static void signCod(SessionManager sessionManager) throws Exception {
Process signingProcess;
@@ -249,4 +246,5 @@ private static void generateAlxFile(WidgetConfig widgetConfig)
writer.write("</loader>" + EOL);
writer.close();
}
+
}
View
745 packager/src/net/rim/tumbler/config/FeatureManager.java
@@ -0,0 +1,745 @@
+/*
+* 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.config;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+import java.util.Vector;
+import java.util.Map.Entry;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import net.rim.tumbler.exception.PackageException;
+import net.rim.tumbler.file.ExtensionDependencyManager;
+import net.rim.tumbler.file.FileManager;
+import net.rim.tumbler.file.Library;
+import net.rim.tumbler.file.Library.Configuration;
+import net.rim.tumbler.file.Library.Extension;
+import net.rim.tumbler.file.Library.Jar;
+import net.rim.tumbler.file.Library.Platform;
+import net.rim.tumbler.file.Library.Src;
+import net.rim.tumbler.file.Library.Target;
+import net.rim.tumbler.log.LogType;
+import net.rim.tumbler.log.Logger;
+import net.rim.tumbler.session.BBWPProperties;
+import net.rim.tumbler.session.SessionManager;
+import net.rim.tumbler.xml.LibraryXMLParser;
+
+public class FeatureManager {
+ // TODO Hardcode platform="JAVA"
+ private String _platform = "JAVA";
+ // TODO Hardcode target="default" until target becomes one of the command
+ // line params in bbwp.exe
+ private String _targetVersion = "default";
+ private HashSet< String > _requiredFeatures;
+ // {featureId, paths & root library.xml info}
+ private Hashtable< String, ExtensionInfo > _repositoryFeatures;
+ // {extensionId, paths & root library.xml info}
+ private Hashtable< String, ExtensionInfo > _extensionLookupTable;
+ private HashSet< String > _resolvedPaths;
+ // By default, "ext" under Tumbler's home, configurable in bbwp.properties
+ private String _repositoryDir;
+ // Common folder contains shared common APIs, folder under _repositoryDir
+ // for storing common API
+ private String _commonAPIDir = "common";
+ private HashSet< String > _extensionClasses;
+ // List of compiled JARs that the extensions might depend on
+ private HashSet< String > _compiledJARDependencies;
+
+ private HashSet< String > _curPaths = new HashSet< String >();
+ private HashSet< String > _commonAPIPaths = new HashSet< String >();
+ private File _temporaryDirectory;
+ // TODO Hardcode features that are not found in extension repository,
+ // temporary workaround until widgetcache extension is moved out of
+ // framework
+ private static HashSet< String > FRAMEWORK_FEATURES = new HashSet< String >();
+
+ private static final String TEMPORARY_DIRECTORY = "~temporaryextensionsource";
+ private static final String EXTENSION_DIRECTORY = "extension";
+ private static final String LIBRARY_XML = "library.xml";
+
+ /**
+ * Stores the extension's library.xml information and the paths to source
+ * code in repository.
+ */
+ public static class ExtensionInfo {
+ private Library _lib;
+ private HashSet<String> _repPaths;
+ private HashSet<String> _jarPaths;
+
+ public ExtensionInfo(Library lib, HashSet<String> repPaths) {
+ _lib = lib;
+ _repPaths = repPaths;
+ }
+
+ public Library getLibrary() {
+ return _lib;
+ }
+
+ /**
+ * @return the extension id found in library.xml, or null if it is not
+ * defined
+ */
+ public String getExtensionId() {
+ if (_lib != null && _lib.getExtension() != null) {
+ return _lib.getExtension().getId();
+ }
+
+ return null;
+ }
+
+ public HashSet<String> getRepositoryPaths() {
+ return _repPaths;
+ }
+
+ public HashSet<String> getCompiledJARPaths() {
+ return _jarPaths;
+ }
+
+ public void addCompiledJARPath(String path) {
+ if (_jarPaths == null) {
+ _jarPaths = new HashSet<String>();
+ }
+
+ _jarPaths.add(path);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("{lib: ");
+ buf.append(_lib);
+ buf.append(", paths: ");
+ buf.append(_repPaths);
+ buf.append("}");
+ return buf.toString();
+ }
+ }
+
+ public FeatureManager(BBWPProperties bbwpProperties,
+ Hashtable<WidgetAccess, Vector<WidgetFeature>> accessTable) {
+ _repositoryFeatures = new Hashtable<String, ExtensionInfo>();
+ _extensionLookupTable = new Hashtable<String, ExtensionInfo>();
+ _resolvedPaths = new HashSet<String>();
+ _repositoryDir = bbwpProperties.getRepositoryDir();
+ _requiredFeatures = getRequiredFeatures(accessTable);
+ _extensionClasses = new HashSet<String>();
+ _compiledJARDependencies = new HashSet<String>();
+
+ // TODO temp workaround, treat widgetcache features as exceptions
+ // will not throw error when the code fails to find them in extension
+ // repository
+ if (FRAMEWORK_FEATURES.isEmpty()) {
+ FRAMEWORK_FEATURES.add("blackberry.widgetcache");
+ FRAMEWORK_FEATURES.add("blackberry.widgetcache.CacheInformation");
+ }
+ }
+
+ private static HashSet<String> getRequiredFeatures(
+ Hashtable<WidgetAccess, Vector<WidgetFeature>> accessTable) {
+ Set<WidgetAccess> keys = accessTable.keySet();
+ HashSet<String> requiredFeatures = new HashSet<String>();
+
+ for (Object accessKey : keys) {
+ Vector<WidgetFeature> features = (Vector<WidgetFeature>) accessTable
+ .get(accessKey);
+
+ for (Object featureObject : features) {
+ WidgetFeature feature = (WidgetFeature) featureObject;
+ requiredFeatures.add(feature.getID());
+ }
+ }
+
+ return requiredFeatures;
+ }
+
+ /**
+ * Given a WebWorks application archive, look at the features specified in
+ * the white list and figure out all the extensions that need to be built.
+ *
+ * @param widgetArchive
+ * WebWorks application archive
+ * @param extJars
+ * zip entries of JAR files found in the archive's "ext" folder
+ * @return a set of file paths of the source code of all extensions that
+ * need to be built
+ * @throws Exception
+ * if problems encountered while resolving extension
+ * dependencies
+ */
+ public HashSet<String> resolveFeatures(ZipFile widgetArchive,
+ HashSet<ZipEntry> extJars) throws Exception {
+ // step 1: resolve features from widget archive ext folder
+ // if JAR files contribute to features from core API, JAR wins
+ if (extJars != null && !extJars.isEmpty()) {
+ resolveFeaturesFromExtJars(widgetArchive, extJars);
+ }
+
+ // step 2: resolve features from repository folder
+ resolveFeaturesFromRepository();
+
+ // step 3: copy common API files to extension folder for code to compile
+ copyCommonAPI();
+
+ return _resolvedPaths;
+ }
+
+ public HashSet<String> getExtensionClasses() {
+ return _extensionClasses;
+ }
+
+ /**
+ * @return folders that need to be copied for common APIs
+ */
+ public HashSet<String> getCommonAPIPaths() {
+ return _commonAPIPaths;
+ }
+
+ /**
+ * @return
+ */
+ public HashSet<String> getCompiledJARDependencies() {
+ return _compiledJARDependencies;
+ }
+
+ /**
+ * Check JARs in widget archive's ext folder <br>
+ * If required features are found in JARs, extract them to source folder <br>
+ * Add paths in HashSet when done
+ */
+ private void resolveFeaturesFromExtJars(ZipFile widgetArchive,
+ HashSet<ZipEntry> extJars) {
+ if (_temporaryDirectory != null) {
+ if (_temporaryDirectory.delete() == false) {
+ Logger.logMessage(LogType.WARNING, "EXCEPTION_DELETING_DIRECTORY",
+ _temporaryDirectory.toString());
+ }
+ }
+ _temporaryDirectory = new File(getTempExtensionPath());
+
+ for (ZipEntry jarFile : extJars) {
+ try {
+ // uncompress the jar into folders
+ File sourceExtension = unzipJarToTempDir(widgetArchive, jarFile);
+
+ if (sourceExtension == null) {
+ Logger.logMessage(LogType.WARNING,
+ "EXCEPTION_FAILING_DECOMPRESS_JAR", jarFile.getName());
+ return;
+ }
+
+ // parse features offered from ext JARs
+ Hashtable<String, ExtensionInfo> eligibleFeatures = getEligibleFeatures(sourceExtension);
+
+ // if any eligible ids exists, move the content of the temp dir
+ // into a permanent location
+ finalizeEligibleIDs(eligibleFeatures);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ File[] tempExten = _temporaryDirectory.listFiles();
+
+ for (File f : tempExten) {
+ FileManager.deleteDirectory(f);
+ }
+ }
+ }
+
+ FileManager.deleteDirectory(_temporaryDirectory);
+ }
+
+ /*
+ * Takes the jar, uncompress it to temp folder, then return its handle in
+ * the temp folder
+ */
+ private File unzipJarToTempDir(ZipFile widgetArchive, ZipEntry jarFile)
+ throws IOException {
+
+ String extensionName = getExtensionName(jarFile.getName());
+ File sourceExtensionJar = null;
+ ZipFile zipFile = null;
+ try {
+ // first copy the zip entry into the extension folder and identify
+ // it as a jar
+ sourceExtensionJar = FileManager.copyZipEntry(widgetArchive,
+ jarFile, getExtensionPath() + extensionName + ".jar");
+
+ zipFile = new ZipFile(sourceExtensionJar);
+ Enumeration<?> enu = zipFile.entries();
+
+ // go through the jar, copy each entry into the temporary folder
+ while (enu.hasMoreElements()) {
+ ZipEntry zipEntry = (ZipEntry) enu.nextElement();
+
+ if (zipEntry.isDirectory()) {
+ continue;
+ }
+
+ FileManager.copyZipEntry(zipFile, zipEntry,
+ getTempExtensionPath() + extensionName + File.separator);
+ }
+ } finally {
+ if (zipFile != null) {
+ zipFile.close();
+ }
+
+ if (sourceExtensionJar != null) {
+ if (sourceExtensionJar.delete() == false) {
+ Logger.logMessage(LogType.WARNING,
+ "EXCEPTION_DELETING_FILE", sourceExtensionJar.toString());
+ }
+ }
+ }
+
+ File[] fileList = _temporaryDirectory.listFiles();
+ for (File f : fileList) {
+ if (extensionName.equals(f.getName())) {
+ return f;
+ }
+ }
+
+ return null;
+ }
+
+ private static String getExtensionName(String extensionName) {
+ if (extensionName == null) {
+ return null;
+ }
+ int fileTypePosition = extensionName.lastIndexOf(".jar");
+ // the zip entry might look like "ext/xxx.jar" or "ext\xxx.jar"
+ // if checking index of "/" gives -1, should check the index of "\"
+ int fileSepPosition = extensionName.lastIndexOf("/");
+
+ if (fileSepPosition < 0) {
+ fileSepPosition = extensionName.lastIndexOf("\\");
+ }
+
+ if (fileTypePosition < 0) {
+ fileTypePosition = extensionName.length();
+ }
+ return extensionName.substring(fileSepPosition + 1, fileTypePosition);
+ }
+
+ private Hashtable<String, ExtensionInfo> getEligibleFeatures(
+ File sourceExtension) {
+ Hashtable<String, ExtensionInfo> eligibleFeatures = new Hashtable<String, ExtensionInfo>();
+
+ File[] files = sourceExtension.listFiles();
+ Hashtable<String, ExtensionInfo> availableFeatures = null;
+
+ // library.xml should at top level
+ for (File f : files) {
+ if (f.getName().equalsIgnoreCase(LIBRARY_XML)) {
+ try {
+ availableFeatures = parseFeaturesInLibraryXML(f, true);
+ } catch (Exception e) {
+ return eligibleFeatures;
+ }
+
+ if (availableFeatures != null) {
+ for (Entry<String, ExtensionInfo> entry : availableFeatures
+ .entrySet()) {
+ eligibleFeatures.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+ }
+
+ return eligibleFeatures;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void finalizeEligibleIDs(Hashtable<String, ExtensionInfo> eligibleFeatures) {
+ for (Entry<String, ExtensionInfo> entry : eligibleFeatures.entrySet()) {
+ String key = entry.getKey();
+ ExtensionInfo value = entry.getValue();
+ if (_requiredFeatures.contains(key)) {
+ copyExtensionPathsToSourceDir(value.getRepositoryPaths());
+ _resolvedPaths.addAll((HashSet<String>) _curPaths.clone());
+ _extensionClasses.add(value.getLibrary().getEntryClass());
+
+ // remove features from the list, so that even if the feature is
+ // available in repository, the repository version will not be used
+ _requiredFeatures.remove(key);
+ }
+ }
+ }
+
+ /**
+ * Resolve features from extension repository
+ */
+ @SuppressWarnings("unchecked")
+ private void resolveFeaturesFromRepository() throws Exception {
+ parseRepository();
+
+ HashSet<String> extensions = new HashSet<String>();
+
+ // derive extensions to be built based on features on white list
+ for (String featureId : _requiredFeatures) {
+ ExtensionInfo info = _repositoryFeatures.get(featureId);
+
+ if (info != null) {
+ String extensionId = info.getExtensionId();
+
+ // unable to build app that uses feature from an extension that
+ // does not have an id
+ // because it is not possible to resolve dependencies
+ if (extensionId != null && !extensionId.isEmpty()) {
+ extensions.add(extensionId);
+
+ // if the extension has any JAR dependencies, add it to the
+ // list so that it gets added to rapc classpath
+ if (info.getCompiledJARPaths() != null) {
+ for (String jarPath : info.getCompiledJARPaths()) {
+ File jarFile = new File(jarPath);
+ _compiledJARDependencies.add(jarFile
+ .getAbsolutePath());
+ }
+ }
+ } else {
+ throw new PackageException(
+ "EXCEPTION_NEED_FEATURE_FROM_UNIDENTIFIED_EXTENSION", featureId);
+ }
+ } else {
+ // TODO temp workaround to not throw error when widgetcache
+ // features cannot be found in repository
+ if (!FRAMEWORK_FEATURES.contains(featureId)) {
+ throw new PackageException("EXCEPTION_FEATURE_NOT_FOUND",
+ featureId);
+ }
+ }
+ }
+
+ // find all extensions that need to be built with dependencies taken
+ // into account
+ ExtensionDependencyManager edm = new ExtensionDependencyManager(
+ _extensionLookupTable);
+ extensions = edm.resolveExtensions(extensions);
+
+ for (String extensionId : extensions) {
+ HashSet<String> repPaths = _extensionLookupTable.get(extensionId)
+ .getRepositoryPaths();
+ copyExtensionPathsToSourceDir(repPaths);
+ _resolvedPaths.addAll((HashSet<String>) _curPaths.clone());
+
+ // extension can be found in lookup table for sure, otherwise
+ // exception would have been thrown in ExtensionDependencyManager.resolve
+ Library lib = _extensionLookupTable.get(extensionId).getLibrary();
+ _extensionClasses.add(lib.getEntryClass());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void copyCommonAPI() {
+ File dir = new File(_repositoryDir + File.separator + _commonAPIDir);
+ File[] files = dir.listFiles();
+
+ for (File f : files) {
+ if (f.exists()) {
+ try {
+ File destFile = new File(getExtensionPath() + f.getName());
+ _curPaths.clear();
+ copyFiles(f, destFile);
+ _commonAPIPaths
+ .addAll((HashSet<String>) _curPaths.clone());
+ } catch (IOException e) {
+ Logger.logMessage(LogType.ERROR, "EXCEPTION_IO_COPY_FILES",
+ new String[] {f.getAbsolutePath(), e.getMessage()});
+ }
+ }
+ }
+ }
+
+ /**
+ * For each folder in the extension repository, look for its library.xml and
+ * parse it to resolve source file paths
+ */
+ private void parseRepository() {
+ File dir = new File(_repositoryDir);
+
+ if (dir.exists() && dir.isDirectory()) {
+ File[] files = dir.listFiles();
+
+ for (File f : files) {
+ if (f.isDirectory()) {
+ File[] extFiles = f.listFiles();
+
+ for (File g : extFiles) {
+ try {
+ if (g.getName().equalsIgnoreCase(LIBRARY_XML)) {
+ Hashtable<String, ExtensionInfo> features = parseFeaturesInLibraryXML(
+ g, false);
+ if (features != null) {
+ _repositoryFeatures.putAll(features);
+ }
+ }
+ } catch (Exception e) {
+ // TODO handle error
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Given a library file, find the configuration element that matches the
+ * current platform and target
+ *
+ * @param lib
+ * @return the configuration that matches the current platform and target
+ */
+ private Configuration getTargetConfiguration(Library lib) {
+ String matchedConfigName = null;
+
+ // check whether platform and target match what we support
+ ArrayList<Platform> platforms = lib.getPlatforms();
+ if (platforms != null) {
+ for (Platform p : platforms) {
+ if (p.getValue().equals(_platform)) {
+ ArrayList<Target> targets = p.getTargets();
+
+ if (targets != null) {
+ for (Target t : targets) {
+ if (t.getVersion().equals(_targetVersion)) {
+ matchedConfigName = t.getConfigName();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // make sure the config is defined
+ if (matchedConfigName != null) {
+ ArrayList<Configuration> configurations = lib.getConfigurations();
+
+ for (Configuration config : configurations) {
+ if (config.getName().equals(matchedConfigName)) {
+ return config;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Helper method for parsing out library.xml into an object
+ *
+ * @param libraryXML
+ * @throws Exception
+ */
+ private static Library parseLibraryXML(File libraryXML) throws Exception {
+ LibraryXMLParser parser = new LibraryXMLParser();
+ return parser.parseXML(libraryXML.getAbsolutePath());
+ }
+
+ /**
+ * Parse a given a library.xml to find out the features it offers and store
+ * the proper set of source file paths for the current platform and target
+ *
+ * @param libraryXML
+ * library.xml file, cannot be null
+ * @param allowBackwardCompatibility
+ * true if it's parsing library.xml from an extension JAR
+ * @return hashtable that contains feature id's and the paths for the source
+ * files, or null if (1) library.xml is malformed, (2) if
+ * allowBackwardCompatibility is false, and <target>,
+ * <configuration>, <platform> or <src> is not specified correctly
+ * @throws Exception
+ */
+ private Hashtable<String, ExtensionInfo> parseFeaturesInLibraryXML(
+ File libraryXML, boolean allowBackwardCompatibility) throws Exception {
+ Library lib = parseLibraryXML(libraryXML);
+
+ if (lib == null) {
+ return null;
+ }
+
+ ArrayList<WidgetFeature> features = lib.getFeatures();
+ HashSet<String> paths = new HashSet<String>();
+ Hashtable<String, ExtensionInfo> availableFeatures = new Hashtable<String, ExtensionInfo>();
+
+ if (allowBackwardCompatibility) {
+ // have to work for library.xml that doesn't contain configuration and platform elements
+ File[] files = _temporaryDirectory.listFiles();
+
+ for (File f : files) {
+ paths.add(f.getAbsolutePath());
+ }
+ } else {
+ ExtensionInfo info = new ExtensionInfo(lib, paths);
+ boolean extensionIdFound = false;
+
+ if (lib.getExtension() != null) {
+ Extension extension = lib.getExtension();
+ String id = extension.getId();
+
+ if (id != null && !id.isEmpty()) {
+ if (_extensionLookupTable.contains(id)) {
+ // more than one library.xml contain the same extension id
+ Logger.logMessage(LogType.WARNING,
+ "VALIDATION_EXTENSION_DEFINED_MORE_THAN_ONCE",
+ new String[] { id });
+ }
+
+ _extensionLookupTable.put(id, info);
+ extensionIdFound = true;
+ }
+ }
+
+ if (!extensionIdFound) {
+ // not considered an error, this extension might not be used
+ // by the app being compiled
+ Logger.logMessage(LogType.WARNING,
+ "VALIDATION_LIBRARYXML_EXTENSION_ID_NOT_DEFINED",
+ new String[] { libraryXML.getAbsolutePath() });
+ }
+
+ Configuration config = getTargetConfiguration(lib);
+
+ if (config == null) {
+ Logger.logMessage(LogType.WARNING, "VALIDATION_LIBRARYXML_NO_CONFIG",
+ new String[] { libraryXML.getAbsolutePath() });
+ return null;
+ }
+
+ ArrayList<Src> src = config.getSrc();
+
+ if (src == null || src.isEmpty()) {
+ Logger.logMessage(LogType.WARNING, "VALIDATION_LIBRARYXML_NO_SRC",
+ new String[] { libraryXML.getAbsolutePath() });
+ return null;
+ }
+
+ File extensionDir = libraryXML.getParentFile();
+
+ for (Src s : src) {
+ String path = s.getPath();
+ paths.add(extensionDir.getAbsolutePath() + File.separator
+ + path);
+ }
+ }
+
+ ExtensionInfo info = new ExtensionInfo(lib, paths);
+
+ for (WidgetFeature feature : features) {
+ availableFeatures.put(feature.getID(), info);
+ }
+
+ if (lib.getCompiledJARDependencies() != null) {
+ for (Jar j : lib.getCompiledJARDependencies()) {
+ String path = j.getPath();
+ File temp = new File(path);
+
+ if (temp.isAbsolute()) {
+ info.addCompiledJARPath(path);
+ } else {
+ info.addCompiledJARPath(libraryXML.getParentFile()
+ .getAbsolutePath()
+ + File.separator + path);
+ }
+ }
+ }
+
+ return availableFeatures;
+ }
+
+ private static String getExtensionPath() {
+ return SessionManager.getInstance().getSourceFolder() + File.separator
+ + EXTENSION_DIRECTORY + File.separator;
+ }
+
+ private static String getTempExtensionPath() {
+ return SessionManager.getInstance().getSourceFolder()
+ + TEMPORARY_DIRECTORY + File.separator;
+ }
+
+ private void copyExtensionPathsToSourceDir(HashSet<String> paths) {
+ _curPaths.clear();
+
+ for (String path : paths) {
+ File file = new File(path);
+
+ if (file.exists()) {
+ try {
+ copyFiles(file, new File(getExtensionPath()
+ + file.getName()));
+ } catch (IOException e) {
+ Logger.logMessage(LogType.ERROR, "EXCEPTION_IO_COPY_FILES",
+ new String[] {file.getAbsolutePath(), e.getMessage()});
+ }
+ }
+ }
+ }
+
+ /**
+ * This method copies file recursively from src to dest
+ */
+ private void copyFiles(File src, File dest) throws IOException {
+ // Check to ensure that the source is valid
+ if (!src.exists()) {
+ throw new IOException("copyFiles: Cannot find source: "
+ + src.getAbsolutePath() + ".");
+ } else if (!src.canRead()) {
+ // check to ensure we have rights to the source
+ throw new IOException("copyFiles: No right to read source: "
+ + src.getAbsolutePath() + ".");
+ }
+
+ // is this a directory copy?
+ if (src.isDirectory()) {
+ if (!dest.exists()) { // does the destination already exist?
+ // if not we need to make it exist if possible (note this is
+ // mkdirs not mkdir)
+ if (!dest.mkdirs()) {
+ throw new IOException(
+ "copyFiles: Could not create direcotry: "
+ + dest.getAbsolutePath() + ".");
+ }
+ }
+
+ String list[] = src.list();
+ // copy all the files in the list.
+ for (String path : list) {
+ File dest1 = new File(dest, path);
+ File src1 = new File(src, path);
+ copyFiles(src1, dest1);
+ }
+ } else {
+ // This was not a directory, just copy the file
+ try {
+ // open the files for input and output
+ FileManager.copyFile(src, dest);
+ _curPaths.add(dest.getAbsolutePath());
+ } catch (IOException e) { // Error copying file
+ IOException wrapper = new IOException(
+ "copyFiles: Unable to copy file: "
+ + src.getAbsolutePath() + " to "
+ + dest.getAbsolutePath() + ".");
+ wrapper.initCause(e);
+ wrapper.setStackTrace(e.getStackTrace());
+ throw wrapper;
+ }
+ }
+ }
+}
View
19 packager/src/net/rim/tumbler/config/WidgetAccess.java
@@ -1,3 +1,18 @@
+/*
+* 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.config;
import java.net.URI;
@@ -12,7 +27,7 @@
public WidgetAccess(String uri, boolean allowSubDomain) throws Exception {
try {
_uri = URI.create(uri);
- // check for a protocol - mks354080
+ // Check for a protocol
if (!(_uri.toString().equals("WidgetConfig.WIDGET_LOCAL_DOMAIN")) &&
(_uri.getScheme() == null || _uri.getScheme().length() == 0)) {
throw new ValidationException (
@@ -24,7 +39,7 @@ public WidgetAccess(String uri, boolean allowSubDomain) throws Exception {
if (host != null
&& SessionManager.getInstance().getTLD().indexOf(
"$$" + host.toLowerCase().trim() + "$$") != -1 && _allowSubDomain) {
- // throw exception - exit compilation
+ // Throw exception - exit compilation
throw new ValidationException( "EXCEPTION_CONFIGXML_TLD", uri );
}
} catch (IllegalArgumentException e) {
View
36 packager/src/net/rim/tumbler/config/WidgetConfig.java
@@ -1,3 +1,18 @@
+/*
+* 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.config;
import java.util.HashMap;
@@ -61,11 +76,13 @@
private boolean _allowInvokeParams;
private String _backgroundSource;
private String _foregroundSource;
- // debug issue
+
+ // Debug issue
private boolean _debugEnabled=false;
public WidgetConfig() {
- // set defaults
+
+ // Set defaults
_accessTable = new Hashtable<WidgetAccess, Vector<WidgetFeature>>();
_hoverIconSrc = new Vector<String>();
_customHeaders = new HashMap<String, String>();
@@ -184,7 +201,7 @@ public void setLoadingScreenColour(String screenColour)
Logger.logMessage(LogType.INFO,
"PROGRESS_VALIDATING_CONFIG_XML_LOADINGSCREEN_COLOR");
}
- // color variable should look like: #000000
+ // Color variable should look like: #000000
String regex = "^#[A-Fa-f0-9]{6}$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(screenColour);
@@ -430,9 +447,9 @@ public Integer getAggressiveCacheAge() {
public void setAggressiveCacheAge(int inputValue) {
// Enable aggressive cache flag if the value is above 0
- if(inputValue > 0){
+ if (inputValue > 0){
setAggressiveCache(true);
- } else if (inputValue==-1) {
+ } else if (inputValue == -1) {
setAggressiveCache(false);
}
@@ -448,10 +465,11 @@ public Integer getMaxCacheSize() {
public void setMaxCacheSize(int inputValue) {
// Min value of 0, max value of 2048 KB
- if(inputValue >= 0 && inputValue <= (2048*1024)){
+ final int kb_2048 = 2048 * 1024;
+ if (inputValue >= 0 && inputValue <= (kb_2048)){
_maxCacheSize = inputValue;
- } else if(inputValue > 2048*1024) {
- _maxCacheSize = 2048*1024;
+ } else if (inputValue > kb_2048) {
+ _maxCacheSize = kb_2048;
}
}
@@ -461,7 +479,7 @@ public Integer getMaxCacheItemSize() {
public void setMaxCacheItemSize(int inputValue) {
// -1 is a valid value
- if(inputValue >= -1){
+ if (inputValue >= -1){
_maxCacheable = inputValue;
}
}
View
32 packager/src/net/rim/tumbler/config/WidgetFeature.java
@@ -1,5 +1,22 @@
+/*
+* 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.config;
+import java.util.Arrays;
+
public class WidgetFeature {
private String _id;
private boolean _isRequired;
@@ -29,4 +46,19 @@ public String getVersion() {
public WidgetFeature[] getDependentFeatures() {
return _dependentFeatures;
}
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("Feature{id: ");
+ buf.append(_id);
+ buf.append(", required: ");
+ buf.append(_isRequired);
+ buf.append(", version: ");
+ buf.append(_version);
+ buf.append(", dependentFeatures: ");
+ buf.append(Arrays.toString(_dependentFeatures));
+ buf.append("}");
+ return buf.toString();
+ }
}
View
15 packager/src/net/rim/tumbler/exception/CommandLineException.java
@@ -1,3 +1,18 @@
+/*
+* 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.exception;
public class CommandLineException extends RuntimeException {
View
19 packager/src/net/rim/tumbler/exception/PackageException.java
@@ -1,7 +1,24 @@
+/*
+* 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.exception;
public class PackageException extends Exception {
- private String _info;
+
+ private static final long serialVersionUID = 1L;
+ private String _info;
public PackageException(String id) {
super(id);
View
15 packager/src/net/rim/tumbler/exception/SessionException.java
@@ -1,3 +1,18 @@
+/*
+* 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.exception;
public class SessionException extends RuntimeException {
View
19 packager/src/net/rim/tumbler/exception/ValidationException.java
@@ -1,7 +1,24 @@
+/*
+* 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.exception;
public class ValidationException extends Exception {
- private String _info;
+
+ private static final long serialVersionUID = 1L;
+ private String _info;
public ValidationException(String id) {
super(id);
View
108 packager/src/net/rim/tumbler/file/ExtensionDependencyManager.java
@@ -0,0 +1,108 @@
+/*
+* 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.file;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.Hashtable;
+
+import net.rim.tumbler.config.FeatureManager.ExtensionInfo;
+import net.rim.tumbler.exception.PackageException;
+import net.rim.tumbler.file.Library.Extension;
+import net.rim.tumbler.log.LogType;
+import net.rim.tumbler.log.Logger;
+
+
+/**
+ * Logic for resolving dependencies for extensions
+ */
+public class ExtensionDependencyManager {
+ private Hashtable<String, ExtensionInfo> _extensionLookupTable;
+
+ private Deque<String> _inProgressStack;
+ private HashSet<String> _resolvedDependencies;
+
+ /**
+ * Constructor
+ *
+ * @param extensionLookupTable
+ * map with extension library info and paths indexed by extension
+ * id, cannot be null
+ */
+ public ExtensionDependencyManager(
+ Hashtable<String, ExtensionInfo> extensionLookupTable) {
+ _extensionLookupTable = extensionLookupTable;
+ _inProgressStack = new ArrayDeque<String>();
+ _resolvedDependencies = new HashSet<String>();
+ }
+
+ private void resolve(HashSet<String> extensions) throws Exception {
+ for (String extId : extensions) {
+ Library info = null;
+
+ if (_extensionLookupTable.get(extId) != null) {
+ info = _extensionLookupTable.get(extId).getLibrary();
+ }
+
+ if (info != null) {
+ _inProgressStack.push(extId);
+ _resolvedDependencies.add(extId);
+
+ ArrayList<Extension> dependencies = info.getDependencies();
+
+ if (dependencies != null && !dependencies.isEmpty()) {
+ HashSet<String> deps = new HashSet<String>();
+
+ for (Extension e : dependencies) {
+ if (!_inProgressStack.contains(e.getId())) {
+ deps.add(e.getId());
+ } else {
+ throw new PackageException("EXCEPTION_CIRCULAR_DEPENDENCY", e.getId());
+ }
+ }
+
+ resolve(deps);
+ }
+
+ _inProgressStack.pop();
+ } else {
+ throw new PackageException("EXCEPTION_EXTENSION_NOT_FOUND", extId);
+ }
+ }
+ }
+
+ /**
+ * Resolve dependencies recursively<br>
+ * Base case: extension does not have any dependencies<br>
+ * <br>
+ *
+ * Push an extension on the stack at the start of the resolve process. The
+ * extension is popped off the stack when all its dependencies have been
+ * resolved.
+ *
+ * @param extensions
+ * @throws Exception
+ * when a circular dependency is detected, or if an extension
+ * listed as a dependency cannot be found in the lookup table
+ */
+ public HashSet<String> resolveExtensions(HashSet<String> extensions)
+ throws Exception {
+ resolve(extensions);
+ return _resolvedDependencies;
+ }
+}
View
616 packager/src/net/rim/tumbler/file/FileManager.java
@@ -1,10 +1,23 @@
+/*
+* 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.file;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -12,7 +25,10 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.FileChannel;
+import java.util.ArrayList;
import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
import java.util.List;
import java.util.Vector;
import java.util.zip.Adler32;
@@ -21,34 +37,30 @@
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
import net.rim.tumbler.WidgetPackager;
+import net.rim.tumbler.config.FeatureManager;
+import net.rim.tumbler.config.WidgetAccess;
+import net.rim.tumbler.config.WidgetFeature;
import net.rim.tumbler.exception.PackageException;
+import net.rim.tumbler.log.LogType;
+import net.rim.tumbler.log.Logger;
import net.rim.tumbler.session.BBWPProperties;
import net.rim.tumbler.session.SessionManager;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
public class FileManager {
- private BBWPProperties _bbwpProperties;
- private Vector<String> _outputFiles;
- private Vector<String> _extensionClasses;
-
- private static final String EOL = System.getProperty("line.separator");
- private static final String FILE_SEP = System.getProperty("file.separator");
- private static final String STANDARD_OUTPUT = "StandardInstall";
- private static final String OTA_OUTPUT = "OTAInstall";
- private static final String EXTENSION_DIRECTORY = "extension";
+ private BBWPProperties _bbwpProperties;
+ private Vector<String> _outputFiles;
+ private FeatureManager _featureManager;
+
+ private static final String NL = System.getProperty("line.separator");
+ private static final String FILE_SEP = System.getProperty("file.separator");
+ private static final String STANDARD_OUTPUT = "StandardInstall";
+ private static final String OTA_OUTPUT = "OTAInstall";
- public FileManager(BBWPProperties bbwpProperties) {
+ public FileManager(BBWPProperties bbwpProperties, Hashtable<WidgetAccess, Vector<WidgetFeature>> accessTable) {
_bbwpProperties = bbwpProperties;
_outputFiles = new Vector<String>();
- _extensionClasses = new Vector<String>();
+ _featureManager = new FeatureManager(bbwpProperties, accessTable);
}
public List<String> getFiles() {
@@ -60,8 +72,14 @@ public void cleanOutput() {
String archiveName = SessionManager.getInstance().getArchiveName();
deleteDirectory(new File(outputDir + FILE_SEP + FileManager.OTA_OUTPUT));
deleteDirectory(new File(outputDir + FILE_SEP + FileManager.STANDARD_OUTPUT));
- (new File(outputDir + FILE_SEP + archiveName + ".jar")).delete();
- (new File(outputDir + FILE_SEP + archiveName + ".rapc")).delete();
+ File jarFile = new File(outputDir + FILE_SEP + archiveName + ".jar");
+ if ( jarFile.exists() && jarFile.delete() == false ) {
+ Logger.logMessage( LogType.WARNING, "EXCEPTION_DELETING_FILE", jarFile.getAbsolutePath());
+ }
+ File rapcFile = new File(outputDir + FILE_SEP + archiveName + ".rapc");
+ if ( rapcFile.exists() && rapcFile.delete() == false ) {
+ Logger.logMessage( LogType.WARNING, "EXCEPTION_DELETING_FILE", rapcFile.getAbsolutePath());
+ }
}
public void cleanSource() {
@@ -69,11 +87,16 @@ public void cleanSource() {
}
public void prepare() throws Exception {
- // clean out source folder
+ // Clean out source folder
deleteDirectory(new File(SessionManager.getInstance().getSourceFolder()));
- (new File(SessionManager.getInstance().getSourceFolder())).mkdirs();
- // copy templates
+ File f = new File(SessionManager.getInstance().getSourceFolder());
+ if ( !(f.exists() && f.isDirectory()) ) {
+ if ( f.mkdirs() == false ) {
+ Logger.logMessage( LogType.WARNING, "EXCEPTION_MAKING_DIRECTORY");
+ }
+ }
+ // Copy templates
try {
TemplateWrapper templateWrapper = new TemplateWrapper(_bbwpProperties);
_outputFiles.addAll(templateWrapper.writeAllTemplates(
@@ -82,12 +105,14 @@ public void prepare() throws Exception {
throw new PackageException("EXCEPTION_IO_TEMPLATES");
}
- // extract archive
+ // Extract archive
ZipFile zip = new ZipFile(new File(SessionManager.getInstance().getWidgetArchive()).getAbsolutePath());
Enumeration<?> en = zip.entries();
String sourceFolder = SessionManager.getInstance().getSourceFolder();
+ HashSet<ZipEntry> extJars = new HashSet<ZipEntry>();
+
while (en.hasMoreElements()) {
- // create output file name
+ // Create output file name
ZipEntry ze = (ZipEntry) en.nextElement();
if (ze.isDirectory())
continue;
@@ -97,30 +122,68 @@ public void prepare() throws Exception {
boolean isRoot = zipEntryFile.getParent() == null;
String fname = sourceFolder + FILE_SEP + zipEntryFile.getPath();
- // extract file
- InputStream is = zip.getInputStream(ze);
- File fi = new File(fname);
- if (!fi.getParentFile().isDirectory() || !fi.getParentFile().exists())
- fi.getParentFile().mkdirs();
- FileOutputStream fos = new FileOutputStream(fname);
- int bytesRead;
- while ((bytesRead = is.read()) != -1)
- fos.write(bytesRead);
- fos.close();
-
- if (zipEntryName.startsWith("ext") && zipEntryName.endsWith(".jar")) {
- populateExtension(fname);
- } else {
- // HACK for icon files not displayed properly if similar named files exist in sub folders
- if (!isRoot) {
- _outputFiles.add(0, fname);
- } else {
- _outputFiles.add(fname);
- }
- }
+ if (zipEntryName.startsWith("ext") && zipEntryName.endsWith(".jar")) {
+ extJars.add(ze);
+ } else {
+ // Extract file
+ copyZipEntry(zip, ze, sourceFolder + FILE_SEP);
+
+ // Hack for icon files not displayed properly if similar named
+ // files exist in sub folders
+ if (!isRoot) {
+ _outputFiles.add(0, fname);
+ } else {
+ _outputFiles.add(fname);
+ }
+ }
}
+
+ copyExtensionFiles(zip, extJars);
+ }
+
+ /**
+ * @param zip
+ * WebWorks application archive
+ * @param extJars
+ * extension JAR zip entries found in archive's "ext" folder
+ * @throws Exception
+ * if there is extensions cannot be resolved
+ */
+ private void copyExtensionFiles(ZipFile zip, HashSet<ZipEntry> extJars) throws Exception {
+ HashSet<String> resolvedExtensionPaths = _featureManager
+ .resolveFeatures(zip, extJars);
+
+ _outputFiles.addAll(resolvedExtensionPaths);
+
+ for (String path : _featureManager.getCommonAPIPaths()) {
+ _outputFiles.add(0, path);
+ }
}
+ public static File copyZipEntry(ZipFile zipFile, ZipEntry zipEntry,
+ String dest) throws IOException {
+ String fname = dest;
+ if (dest.endsWith(FILE_SEP)) {
+ fname = dest + new File(zipEntry.getName()).getPath();
+ }
+ InputStream is = zipFile.getInputStream(zipEntry);
+ File fi = new File(fname);
+ if (!fi.getParentFile().isDirectory() || !fi.getParentFile().exists()) {
+ if (fi.getParentFile().mkdirs() == false) {
+ Logger.logMessage(LogType.WARNING,
+ "EXCEPTION_MAKING_DIRECTORY", fi.getParentFile().toString());
+ }
+ }
+ FileOutputStream fos = new FileOutputStream(fname);
+ int bytesRead;
+ while ((bytesRead = is.read()) != -1) {
+ fos.write(bytesRead);
+ }
+ fos.close();
+
+ return fi;
+ }
+
// Generate .jdp and .jdw files
public void generateProjectFiles(
String sourceDir,
@@ -143,127 +206,131 @@ public void generateProjectFiles(
fileName = sourceDir + FILE_SEP + codName + ".jdw";
writer = new BufferedWriter(new FileWriter(fileName));
- writer.write("## RIM Java Development Environment" + EOL);
- writer.write("# RIM Workspace file" + EOL);
- writer.write("#" + EOL);
- writer.write("# This file is generated and managed by BlackBerry developer tools."+ EOL);
- writer.write("# It SHOULD NOT BE modified manually." + EOL);
- writer.write("#" + EOL);
- writer.write("[BuildConfigurations" + EOL);
- writer.write("Debug" + EOL);
- writer.write("Release" + EOL);
- writer.write("]" + EOL);
- writer.write("DependenciesInWorkspace=0" + EOL);
- writer.write("[ImplicitRules" + EOL);
- writer.write("]" + EOL);
- writer.write("[Imports" + EOL);
- writer.write("]" + EOL);
- writer.write("[Projects" + EOL);
- writer.write(codName + ".jdp" + EOL);
+ writer.write("## RIM Java Development Environment" + NL);
+ writer.write("# RIM Workspace file" + NL);
+ writer.write("#" + NL);
+ writer.write("# This file is generated and managed by BlackBerry developer tools."+ NL);
+ writer.write("# It SHOULD NOT BE modified manually." + NL);
+ writer.write("#" + NL);
+ writer.write("[BuildConfigurations" + NL);
+ writer.write("Debug" + NL);
+ writer.write("Release" + NL);
+ writer.write("]" + NL);
+ writer.write("DependenciesInWorkspace=0" + NL);
+ writer.write("[ImplicitRules" + NL);
+ writer.write("]" + NL);
+ writer.write("[Imports" + NL);
+ writer.write("]" + NL);
+ writer.write("[Projects" + NL);
+ writer.write(codName + ".jdp" + NL);
// Alternate entry project
if(backgroundSource!=null&&isStartupEnabled) {
- writer.write("runOnStartup.jdp" + EOL);
+ writer.write("runOnStartup.jdp" + NL);
}
- writer.write("]" + EOL);
- writer.write("[ReleaseActiveProjects" + EOL);
- writer.write(codName + ".jdp" + EOL);
- writer.write("]" + EOL);
+ writer.write("]" + NL);
+ writer.write("[ReleaseActiveProjects" + NL);
+ writer.write(codName + ".jdp" + NL);
+ writer.write("]" + NL);
writer.close();
// jdp file
fileName = sourceDir + FILE_SEP + codName + ".jdp";
writer = new BufferedWriter(new FileWriter(fileName));
- writer.write("## RIM Java Development Environment" + EOL);
- writer.write("# RIM Project file" + EOL);
- writer.write("#" + EOL);
- writer.write("# This file is generated and managed by BlackBerry developer tools."+ EOL);
- writer.write("# It SHOULD NOT BE modified manually." + EOL);
- writer.write("#" + EOL);
- writer.write("AddOn=0" + EOL);
- writer.write("AlwaysBuild=0" + EOL);
- writer.write("[AlxImports" + EOL);
- writer.write("]" + EOL);
- writer.write("AutoRestart=0" + EOL);
- writer.write("[ClassProtection" + EOL);
- writer.write("]" + EOL);
- writer.write("[CustomBuildFiles" + EOL);
- writer.write("]" + EOL);
- writer.write("[CustomBuildRules" + EOL);
- writer.write("]" + EOL);
- writer.write("[DefFiles" + EOL);
- writer.write("]" + EOL);
- writer.write("[DependsOn" + EOL);
- writer.write("]" + EOL);
- writer.write("ExcludeFromBuildAll=0" + EOL);
- writer.write("Exported=0" + EOL);
-
- writer.write("[Files" + EOL);
+ writer.write("## RIM Java Development Environment" + NL);
+ writer.write("# RIM Project file" + NL);
+ writer.write("#" + NL);
+ writer.write("# This file is generated and managed by BlackBerry developer tools."+ NL);
+ writer.write("# It SHOULD NOT BE modified manually." + NL);
+ writer.write("#" + NL);
+ writer.write("AddOn=0" + NL);
+ writer.write("AlwaysBuild=0" + NL);
+ writer.write("[AlxImports" + NL);
+ writer.write("]" + NL);
+ writer.write("AutoRestart=0" + NL);
+ writer.write("[ClassProtection" + NL);
+ writer.write("]" + NL);
+ writer.write("[CustomBuildFiles" + NL);
+ writer.write("]" + NL);
+ writer.write("[CustomBuildRules" + NL);
+ writer.write("]" + NL);
+ writer.write("[DefFiles" + NL);
+ writer.write("]" + NL);
+ writer.write("[DependsOn" + NL);
+ writer.write("]" + NL);
+ writer.write("ExcludeFromBuildAll=0" + NL);
+ writer.write("Exported=0" + NL);
+
+ writer.write("[Files" + NL);
for (int i = 0; i < inputFiles.size(); ++i) {
String inputFile = inputFiles.get(i);
inputFile = inputFile.substring(sourceDir.length() + 1);
- writer.write(inputFile + EOL);
+ writer.write(inputFile + NL);
}
- writer.write("]" + EOL);
+ writer.write("]" + NL);
- writer.write("HaveAlxImports=0" + EOL);
- writer.write("HaveDefs=0" + EOL);
- writer.write("HaveImports=1" + EOL);
+ writer.write("HaveAlxImports=0" + NL);
+ writer.write("HaveDefs=0" + NL);
+ writer.write("HaveImports=1" + NL);
- writer.write("[Icons" + EOL);
+ writer.write("[Icons" + NL);
if (icons != null) {
for (int i = 0; i < icons.size(); ++i) {
- writer.write(icons.elementAt(i) + EOL);
+ writer.write(icons.elementAt(i) + NL);
}
}
- writer.write("]" + EOL);
+ writer.write("]" + NL);
- writer.write("[ImplicitRules" + EOL);
- writer.write("]" + EOL);
+ writer.write("[ImplicitRules" + NL);
+ writer.write("]" + NL);
- writer.write("[Imports" + EOL);
+ writer.write("[Imports" + NL);
for (int i = 0; i < libraryFiles.size(); ++i) {
String libraryFile = libraryFiles.get(i);
- writer.write(libraryFile + EOL);
+ writer.write(libraryFile + NL);
+ }
+
+ for (String file : _featureManager.getCompiledJARDependencies()) {
+ writer.write(file + NL);
}
- writer.write("]" + EOL);
+ writer.write("]" + NL);
- writer.write("Listing=0" + EOL);
+ writer.write("Listing=0" + NL);
if(contentSource!=null) {
- writer.write("MidletClass=rim:foreground"+EOL);
+ writer.write("MidletClass=rim:foreground"+NL);
} else {
- writer.write("MidletClass="+EOL);
+ writer.write("MidletClass="+NL);
}
- writer.write("Options=-quiet -deprecation" + EOL);
- writer.write("OutputFileName=" + codName + EOL);
- writer.write("[PackageProtection" + EOL);
- writer.write("]" + EOL);
- writer.write("Platform=0" + EOL);
- writer.write("RibbonPosition=0" + EOL);
-
- writer.write("[RolloverIcons" + EOL);
+ writer.write("Options=-quiet -deprecation" + NL);
+ writer.write("OutputFileName=" + codName + NL);
+ writer.write("[PackageProtection" + NL);
+ writer.write("]" + NL);
+ writer.write("Platform=0" + NL);
+ writer.write("RibbonPosition=0" + NL);
+
+ writer.write("[RolloverIcons" + NL);
if (hoverIcons != null) {
for (int i = 0; i < hoverIcons.size(); ++i) {
- writer.write(hoverIcons.elementAt(i) + EOL);
+ writer.write(hoverIcons.elementAt(i) + NL);
}
}
- writer.write("]" + EOL);
+ writer.write("]" + NL);
- writer.write("RunOnStartup=0" + EOL);
- writer.write("StartupTier=7" + EOL);
+ writer.write("RunOnStartup=0" + NL);
+ writer.write("StartupTier=7" + NL);
if(contentSource!=null&&contentSource.length()!=0) {
- writer.write("SystemModule=0" + EOL);
+ writer.write("SystemModule=0" + NL);
} else {
- writer.write("SystemModule=1" + EOL);
+ writer.write("SystemModule=1" + NL);
}
- writer.write("Title=" + appName + EOL);
- writer.write("Type=0" + EOL);
- if (appVendor != null) { writer.write("Vendor=" + appVendor + EOL); }
- writer.write("Version=" + appVersion + EOL);
+ writer.write("Title=" + appName + NL);
+ writer.write("Type=0" + NL);
+ if (appVendor != null) { writer.write("Vendor=" + appVendor + NL); }
+ writer.write("Version=" + appVersion + NL);
writer.close();
@@ -277,71 +344,71 @@ public void generateProjectFiles(
fileName = sourceDir + FILE_SEP + "runOnStartup.jdp";
writer = new BufferedWriter(new FileWriter(fileName));
- writer.write("## RIM Java Development Environment" + EOL);
- writer.write("# RIM Project file" + EOL);
- writer.write("#" + EOL);
- writer.write("# This file is generated and managed by BlackBerry developer tools."+ EOL);
- writer.write("# It SHOULD NOT BE modified manually." + EOL);
- writer.write("#" + EOL);
- writer.write("AddOn=0" + EOL);
- writer.write("AlwaysBuild=0" + EOL);
- writer.write("[AlxImports" + EOL);
- writer.write("]" + EOL);
- writer.write("AutoRestart=0" + EOL);
- writer.write("[ClassProtection" + EOL);
- writer.write("]" + EOL);
- writer.write("[CustomBuildFiles" + EOL);
- writer.write("]" + EOL);
- writer.write("[CustomBuildRules" + EOL);
- writer.write("]" + EOL);
- writer.write("[DefFiles" + EOL);
- writer.write("]" + EOL);
- writer.write("[DependsOn" + EOL);
- writer.write("]" + EOL);
- writer.write("EntryFor="+codName+EOL);
- writer.write("ExcludeFromBuildAll=0" + EOL);
- writer.write("Exported=0" + EOL);
-
- writer.write("[Files" + EOL);
- writer.write("]" + EOL);
-
- writer.write("HaveAlxImports=0" + EOL);
- writer.write("HaveDefs=0" + EOL);
- writer.write("HaveImports=1" + EOL);
-
- writer.write("[Icons" + EOL);
- writer.write("]" + EOL);
-
- writer.write("[ImplicitRules" + EOL);
- writer.write("]" + EOL);
-
- writer.write("[Imports" + EOL);
- writer.write("]" + EOL);
-
- writer.write("Listing=0" + EOL);
+ writer.write("## RIM Java Development Environment" + NL);
+ writer.write("# RIM Project file" + NL);
+ writer.write("#" + NL);
+ writer.write("# This file is generated and managed by BlackBerry developer tools."+ NL);
+ writer.write("# It SHOULD NOT BE modified manually." + NL);
+ writer.write("#" + NL);
+ writer.write("AddOn=0" + NL);
+ writer.write("AlwaysBuild=0" + NL);
+ writer.write("[AlxImports" + NL);
+ writer.write("]" + NL);
+ writer.write("AutoRestart=0" + NL);
+ writer.write("[ClassProtection" + NL);
+ writer.write("]" + NL);
+ writer.write("[CustomBuildFiles" + NL);
+ writer.write("]" + NL);
+ writer.write("[CustomBuildRules" + NL);
+ writer.write("]" + NL);
+ writer.write("[DefFiles" + NL);
+ writer.write("]" + NL);
+ writer.write("[DependsOn" + NL);
+ writer.write("]" + NL);
+ writer.write("EntryFor="+codName+NL);
+ writer.write("ExcludeFromBuildAll=0" + NL);
+ writer.write("Exported=0" + NL);
+
+ writer.write("[Files" + NL);
+ writer.write("]" + NL);
+
+ writer.write("HaveAlxImports=0" + NL);
+ writer.write("HaveDefs=0" + NL);
+ writer.write("HaveImports=1" + NL);
+
+ writer.write("[Icons" + NL);
+ writer.write("]" + NL);
+
+ writer.write("[ImplicitRules" + NL);
+ writer.write("]" + NL);
+
+ writer.write("[Imports" + NL);
+ writer.write("]" + NL);
+
+ writer.write("Listing=0" + NL);
- writer.write("MidletClass=rim:runOnStartup"+EOL);
- writer.write("Options=-quiet -deprecation" + EOL);
- writer.write("OutputFileName=" + codName + EOL);
- writer.write("[PackageProtection" + EOL);
- writer.write("]" + EOL);
- writer.write("Platform=0" + EOL);
- writer.write("RibbonPosition=0" + EOL);
-
- writer.write("[RolloverIcons" + EOL);
+ writer.write("MidletClass=rim:runOnStartup"+NL);
+ writer.write("Options=-quiet -deprecation" + NL);
+ writer.write("OutputFileName=" + codName + NL);
+ writer.write("[PackageProtection" + NL);
+ writer.write("]" + NL);
+ writer.write("Platform=0" + NL);
+ writer.write("RibbonPosition=0" + NL);
+
+ writer.write("[RolloverIcons" + NL);
if (hoverIcons != null) {
for (int i = 0; i < hoverIcons.size(); ++i) {
- writer.write(hoverIcons.elementAt(i) + EOL);
+ writer.write(hoverIcons.elementAt(i) + NL);
}
}
- writer.write("]" + EOL);
- writer.write("RunOnStartup=1" + EOL);
- writer.write("StartupTier=7" + EOL);
- writer.write("SystemModule=1" + EOL);
- writer.write("Title=" + appName + EOL);
- writer.write("Type=3" + EOL);
- if (appVendor != null) { writer.write("Vendor=" + appVendor + EOL); }
- writer.write("Version=" + appVersion + EOL);
+ writer.write("]" + NL);
+ writer.write("RunOnStartup=1" + NL);
+ writer.write("StartupTier=7" + NL);
+ writer.write("SystemModule=1" + NL);
+ writer.write("Title=" + appName + NL);
+ writer.write("Type=3" + NL);
+ if (appVendor != null) { writer.write("Vendor=" + appVendor + NL); }
+ writer.write("Version=" + appVersion + NL);
writer.close();
@@ -352,7 +419,12 @@ public void writeToSource(byte[] fileToWrite, String relativeFile) throws Except
try {
String s = SessionManager.getInstance().getSourceFolder() + FILE_SEP + relativeFile;
if (!new File(s).exists()) {
- new File(s).getParentFile().mkdirs();
+ File pf = (new File(s)).getParentFile();
+ if ( pf != null && !(pf.exists() && pf.isDirectory()) ) {
+ if ( pf.mkdirs() == false ) {
+ Logger.logMessage( LogType.WARNING, "EXCEPTION_MAKING_DIRECTORY");
+ }
+ }
}
FileOutputStream fos = new FileOutputStream(s);
fos.write(fileToWrite);
@@ -392,29 +464,32 @@ public void copyOutputsFromSource() throws Exception {
private void expandCod(File codFile) throws Exception {
- // if the codFile can be unzipped,
- // then the cod is too big and actually in the zip format with smaller
- // cods inside
- // otherwise, the cod is already a good cod
+ // If the codFile can be unzipped, then the cod is too big
+ // and actually in the zip format with smaller (sibling) cods
+ // inside. Otherwise, the cod is already a good cod.
ZipFile zipFile;
- // check for file's existence
- if (!codFile.exists()) {
+ // Check for file's existence
+ if (!codFile.exists())
throw new PackageException("EXCEPTION_COD_NOT_FOUND");
- } else {
- try {
- zipFile = new ZipFile(codFile);
- zipFile.close();
- } catch (Exception e) {
- return; // this is a not a zip file and thus, not a big cod
- }
+
+ boolean containsSiblingCods;
+
+ try {
+ zipFile = new ZipFile(codFile);
+ zipFile.close();
+ containsSiblingCods = true;
+ } catch (Exception e) {
+ containsSiblingCods = false;
}
+
+ if(!containsSiblingCods)
+ return;
FileInputStream fis = new FileInputStream(codFile);
CheckedInputStream checksum = new CheckedInputStream(fis, new Adler32());
- ZipInputStream zis = new ZipInputStream(new BufferedInputStream(
- checksum));
+ ZipInputStream zis = new ZipInputStream(new BufferedInputStream(checksum));
ZipEntry entry;
BufferedOutputStream dest = null;
@@ -431,10 +506,17 @@ private void expandCod(File codFile) throws Exception {
+ "OTAInstall"
+ FILE_SEP + entry.getName());
- f.getParentFile().mkdirs();
- f.createNewFile();
+ if( f.getParentFile() != null && !(f.getParentFile().exists() && f.getParentFile().isDirectory()) ) {
+ if( f.getParentFile().mkdirs() == false ) {
+ Logger.logMessage( LogType.WARNING, "EXCEPTION_MAKING_DIRECTORY", f.toString());
+ }
+ }
+
+ if( !f.exists() && f.createNewFile() == false ) {
+ Logger.logMessage( LogType.WARNING, "EXCEPTION_CREATING_FILE", f.toString());
+ }
- // write the files to the disk
+ // Write the files to the disk
FileOutputStream fos = new FileOutputStream(f);
dest = new BufferedOutputStream(fos, BUFFER_SIZE);
while ((count = zis.read(data, 0, BUFFER_SIZE)) != -1) {
@@ -452,7 +534,7 @@ public static void copyFile(File in, File out) throws IOException {
FileChannel inChannel = new FileInputStream(in).getChannel();
FileChannel outChannel = new FileOutputStream(out).getChannel();
try {
- // windows is limited to 64mb chunks
+ // Windows is limited to 64mb chunks
long size = inChannel.size();
long position = 0;
while (position < size)
@@ -466,23 +548,28 @@ public static void copyFile(File in, File out) throws IOException {
}
}
- private void createOutputDirs(String outputFolder)
- {
+ private void createOutputDirs(String outputFolder) {
File standardInstallDir = new File(outputFolder + File.separator + FileManager.STANDARD_OUTPUT);
File otaInstallDir = new File(outputFolder + File.separator + FileManager.OTA_OUTPUT);
if (!(standardInstallDir.exists() && standardInstallDir.isDirectory())) {
- standardInstallDir.mkdirs();
+ if (standardInstallDir.mkdirs() == false) {
+ Logger.logMessage(LogType.WARNING, "EXCEPTION_MAKING_DIRECTORY",
+ standardInstallDir.toString());
+ }
}
if (!(otaInstallDir.exists() && otaInstallDir.isDirectory())) {
- otaInstallDir.mkdirs();
+ if (otaInstallDir.mkdirs() == false) {
+ Logger.logMessage(LogType.WARNING, "EXCEPTION_MAKING_DIRECTORY",
+ otaInstallDir.toString());
+ }
}
}
- // delete a dir
- private boolean deleteDirectory(File dir) {
- // remove files first
+ // Delete a dir
+ public static boolean deleteDirectory(File dir) {
+ // Remove files first
if (dir.exists() && dir.isDirectory()) {
String[] children = dir.list();
for (String child : children) {
@@ -491,94 +578,21 @@ private boolean deleteDirectory(File dir) {
}
}
if (dir.exists()) {
- // then remove the directory
+ // Then remove the directory
return dir.delete();
}
return false;
}
-
- private void populateExtension(String extensionArchive) throws Exception {
- // create the extension directory
- String extensionPath = SessionManager.getInstance().getSourceFolder() + FILE_SEP + EXTENSION_DIRECTORY + FILE_SEP;
- (new File(extensionPath)).mkdirs();
-
- // extract all resource files in archive
- ZipFile zip = new ZipFile(new File(extensionArchive).getAbsolutePath());
- Enumeration<?> en = zip.entries();
- while (en.hasMoreElements()) {
- ZipEntry ze = (ZipEntry) en.nextElement();
- if (ze.isDirectory())
- continue;
-
- String zipEntryName = ze.getName();
- File zipEntryFile = new File(zipEntryName);
- String fname = extensionPath + zipEntryFile.getPath();
-
- InputStream is = zip.getInputStream(ze);
- File fi = new File(fname);