'. '

ObfuscatePerLibrary

From APIDesign

(Difference between revisions)
Jump to: navigation, search
(Design)
Current revision (06:13, 29 May 2015) (edit) (undo)
(Checklist)
 
(20 intermediate revisions not shown.)
Line 1: Line 1:
-
[[Bck2Brwsr]] supports static obfuscation mode when whole application is converted into a gigantic static [[JavaScript]]. This is not much different to what [[GWT]] does. However that looses the dynamic nature of [[Java]] and thus I'd like to achieve a state when we will do obfuscation per library - e.g. [[JAR]] file. Only some package (possibly individual classes) could be exported. By default everything would be hidden (obviously all private and package private methods).
+
In contrast to other efforts that try to bring [[Java]] [[Bck2Brwsr|back to browser]], the [[Bck2Brwsr]] [[VM]] supports per [[JAR]] ahead of time compilation, including obfuscation (via [[wikipedia:Closure_compiler#Closure_Compiler|Closure compiler]]). This keeps the dynamic nature of [[Java]], when you compile units independently and then link them into final application on application start. [[I]] believe this is way better than classic static obfuscation mode when whole application is converted into a gigantic static [[JavaScript]] (like [[GWT]] and currently also [[TeaVM]] does).
-
I hope this could give us the benefits of deep obfuscation (most of the classes obfuscated) with ability to link individual libraries in an incremental fashion. Moreover we would not need enormous gigs of memory to compile modestly large applications.
+
== Exported Packages ==
-
== Alternative Deployment ==
+
Right now [[Bck2brwsr]] requires presence of [[OSGi]] headers in manifest. Only packages enumerated in ''Export-Package'' get exported and can be used by other [[JAR]] files (since [[Bck2Brwsr 0.12]] also [[NetBeans]] specific ''OpenIDE-Module-Public-Packages'' tag is recognized). All other classes remain internal to the [[JAR]] file - they can be used from other classes in the [[JAR]], but are hidden externally. This allows us to use full obfuscation mode for these classes - e.g. completely rename their class, method or field names. This leads to much shorter code and faster download times.
-
Browsers are optimized for consuming [[JavaScript]] (compressed by [[GZip]]). We tried to use [[ZIP]], but it is not the most effective solution. That is why let's modify our [[maven]] archetype to generate alternative .js.gzip file for per [[JAR]] file. If the [[JavaScript]] file is found, let [[bck2brwsr]] use it. If not, let [bck2brwsr]] download and use the [[JAR]] file.
+
In case one needs to use a non-[[OSGi]] library [[JAR]], there is a simple way to create an [[OSGiWrapper]] around it.
-
=== Design ===
+
== Faster Compilation ==
-
Define '''@Exported''' annotation to put on packages, classes, methods. This exported elements need to stick to fixed identifier.
+
Per library obfuscation may also speed up compilation. Your libraries can be [[Bck2BrwsrLibraries|compiled just once]] and when you build your application you can re-use them and compile only classes of your application. This is possible now when invoking the [[Bck2Brwsr]] compiler manually (see ahead-of-time section in [[Bck2BrwsrJavadoc]]), and you can also configure your project to prepare [[Bck2BrwsrLibraries]] for others.
-
Do as much calls as possible inside a library with obfuscated names. Private, package private methods should be obfuscated (unless '''@Exported'''). Classes in non-exported packages can have everything obfuscated (unless implement exported symbol). Exported classes should generate something like this:
+
== Fast and Parallel Downloading ==
 +
 
 +
When one sets up the [[Bck2Brwsr]] [[VM]] by calling
 +
<source lang="javascript">
 +
var vm = bck2brwsr(['library1.jar', 'library2.jar', 'app.jar'])
 +
vm.loadClass('app.MainClass').invoke('main');
 +
</source>
 +
the [[VM]] loads appropriate 'library1.js' & co. on background and in parallel. Once they are all available specified application class is loaded and its method is invoked.
 +
 
 +
[[ObfuscatePerLibrary|Per library obfuscation]] is a way to minimize download time, as popular libraries can be hosted on a single website and shared between different applications. Then browsers can cache them and minimize the time needed to start [[Bck2Brwsr]] any application. [[Bck2Brwsr]] [[Maven]] archetype does not automate usage of such central repository of [[Bck2BrwsrLibraries]] (as of May 2015).
 +
 
 +
== Design ==
 +
 
 +
Browsers are optimized for consuming [[JavaScript]] (compressed by [[GZip]]). We tried to use [[ZIP]], but it was not the most effective solution. That is why our current [[Maven]] archetype generates alternative .js file for per [[JAR]] file. If the [[JavaScript]] file is found, let [[bck2brwsr]] use it. If not, [[Bck2Brwsr]] downloads and uses the [[JAR]] file.
 +
 
 +
There is a special '''@Exported''' annotation one can use to annotate packages, classes, methods. This exported elements need to stick to fixed identifier. In addition to that the [[Maven]] plugin recognizes [[OSGi]] manifest and exports all public classes in packages exported via ''Export-Package'' manifest header as well as ''OpenIDE-Module-Public-Packages'' header.
 +
 
 +
As much calls as possible inside a library is done with obfuscated names. Private, package private methods are obfuscated (unless '''@Exported'''). Classes in non-exported packages can have everything obfuscated (unless implement exported symbol). Exported classes generate [[JavaScript]] of following form:
<source lang="javascript">
<source lang="javascript">
Line 29: Line 46:
p['myFunction_V'] = org_nb_test_Clazz.impl_myFunction_V;
p['myFunction_V'] = org_nb_test_Clazz.impl_myFunction_V;
-
p.callMyFunction_V = function() { return this['myFunction_V'](); }
+
org_nb_test_Clazz.myFunction_V = function() { return this['myFunction_V'](); }
}
}
</source>
</source>
-
Need to generate [[JavaScript]] which can be loaded into [[Bck2Brwsr]] [[VM]]. E.g. the actual '''vm''' object is already created and need to be passed to the generated script (investigate [http://requirejs.org/ requirejs.org]). The script assumes existence of method ''registerLibrary'' in the calling context:
+
Need to generate [[JavaScript]] which can be loaded into [[Bck2Brwsr]] [[VM]]. E.g. the actual '''vm''' object is already created and need to be passed to the generated script. The script assumes existence of method ''registerLibrary'' in the calling context:
<source lang="javascript">
<source lang="javascript">
Line 44: Line 61:
As soon as one does var vm = bck2brwsr(...) all the provided libraries will be loaded.
As soon as one does var vm = bck2brwsr(...) all the provided libraries will be loaded.
-
=== TODO ===
+
=== Checklist ===
 +
 
 +
* Introduce '''@Exported''' [[annotation]] and modify obfuscation to also mange package private members (integrated in [[Bck2Brwsr 0.9]])
 +
* Encode resources from a [[JAR]] into [[JavaScript]]. Probably via [[wikipedia:base64]] (also done in [[Bck2Brwsr 0.9]])
 +
* Modify [[Maven]] task to process single [[JAR]] in a batch - can [[Bck2BrwsrLibraries|precompile libraries]] since [[Bck2Brwsr 0.12]]
 +
 
 +
== Conclusion ==
 +
 
 +
The way [[Bck2BrwsrLibraries]] work shows one can have modularity in a single classloader (as [[Bck2Brwsr]] loads all classes in a system {{JDK|java/lang|ClassLoader}}). Yet, it is possible to isolate non-public packages between individual modules and achieve sufficient level of [[modular]] encapsulation. In addition to that one can build such kind of new modularity on top of existing concepts ([[NetBeans Runtime Container]] and/or [[OSGi]] manifest metadata), increase interoperability between those systems and reuse their existing tooling.
 +
 
 +
Will [[Jigsaw]] follow [[Bck2Brwsr]]'s success?
[[Category:Bck2Brwsr]]
[[Category:Bck2Brwsr]]

Current revision

In contrast to other efforts that try to bring Java back to browser, the Bck2Brwsr VM supports per JAR ahead of time compilation, including obfuscation (via Closure compiler). This keeps the dynamic nature of Java, when you compile units independently and then link them into final application on application start. I believe this is way better than classic static obfuscation mode when whole application is converted into a gigantic static JavaScript (like GWT and currently also TeaVM does).

Contents

Exported Packages

Right now Bck2brwsr requires presence of OSGi headers in manifest. Only packages enumerated in Export-Package get exported and can be used by other JAR files (since Bck2Brwsr 0.12 also NetBeans specific OpenIDE-Module-Public-Packages tag is recognized). All other classes remain internal to the JAR file - they can be used from other classes in the JAR, but are hidden externally. This allows us to use full obfuscation mode for these classes - e.g. completely rename their class, method or field names. This leads to much shorter code and faster download times.

In case one needs to use a non-OSGi library JAR, there is a simple way to create an OSGiWrapper around it.

Faster Compilation

Per library obfuscation may also speed up compilation. Your libraries can be compiled just once and when you build your application you can re-use them and compile only classes of your application. This is possible now when invoking the Bck2Brwsr compiler manually (see ahead-of-time section in Bck2BrwsrJavadoc), and you can also configure your project to prepare Bck2BrwsrLibraries for others.

Fast and Parallel Downloading

When one sets up the Bck2Brwsr VM by calling

var vm = bck2brwsr(['library1.jar', 'library2.jar', 'app.jar'])
vm.loadClass('app.MainClass').invoke('main');

the VM loads appropriate 'library1.js' & co. on background and in parallel. Once they are all available specified application class is loaded and its method is invoked.

Per library obfuscation is a way to minimize download time, as popular libraries can be hosted on a single website and shared between different applications. Then browsers can cache them and minimize the time needed to start Bck2Brwsr any application. Bck2Brwsr Maven archetype does not automate usage of such central repository of Bck2BrwsrLibraries (as of May 2015).

Design

Browsers are optimized for consuming JavaScript (compressed by GZip). We tried to use ZIP, but it was not the most effective solution. That is why our current Maven archetype generates alternative .js file for per JAR file. If the JavaScript file is found, let bck2brwsr use it. If not, Bck2Brwsr downloads and uses the JAR file.

There is a special @Exported annotation one can use to annotate packages, classes, methods. This exported elements need to stick to fixed identifier. In addition to that the Maven plugin recognizes OSGi manifest and exports all public classes in packages exported via Export-Package manifest header as well as OpenIDE-Module-Public-Packages header.

As much calls as possible inside a library is done with obfuscated names. Private, package private methods are obfuscated (unless @Exported). Classes in non-exported packages can have everything obfuscated (unless implement exported symbol). Exported classes generate JavaScript of following form:

function org_nb_test_Clazz() {
 
}
vm['org/nb/test/Clazz'] = org_nb_test_Clazz;

public or protected non-final methods need to be exported in an overridable style:

function org_nb_test_Clazz() {
  var p = ...;
 
  org_nb_test_Clazz.impl_myFunction_V = function () { ... };
 
  p['myFunction_V'] = org_nb_test_Clazz.impl_myFunction_V;
  org_nb_test_Clazz.myFunction_V = function() { return this['myFunction_V'](); }
}

Need to generate JavaScript which can be loaded into Bck2Brwsr VM. E.g. the actual vm object is already created and need to be passed to the generated script. The script assumes existence of method registerLibrary in the calling context:

registerLibrary(/*['dep','anotherDep','moreDep']*/, function (vm) {
  // when invoked register all own classes and their methods into the vm object
});

As soon as one does var vm = bck2brwsr(...) all the provided libraries will be loaded.

Checklist

Conclusion

The way Bck2BrwsrLibraries work shows one can have modularity in a single classloader (as Bck2Brwsr loads all classes in a system ClassLoader). Yet, it is possible to isolate non-public packages between individual modules and achieve sufficient level of modular encapsulation. In addition to that one can build such kind of new modularity on top of existing concepts (NetBeans Runtime Container and/or OSGi manifest metadata), increase interoperability between those systems and reuse their existing tooling.

Will Jigsaw follow Bck2Brwsr's success?

Personal tools
buy