public class PreferredListGen extends Object
PreferredClassLoader. The list is generated by examining the dependencies of classes contained within a target JAR file and zero or more additional supporting JAR files. Through various command-line options, a set of "root" classes are identified as belonging to a public API. These root classes provide the starting point for recursively computing a dependency graph, finding all of the classes referenced in the public API of the root classes, finding all of the classes referenced in turn by the public API of those classes, and so on, until no new classes are found. The results of the dependency analysis are combined with the preferred list information in the additional supporting JAR files to compute a preferred list having the smallest number of entries that describes the preferred state of the classes and resources contained in all of the JAR files. The output of the tool is a new version of the target JAR file containing the generated preferred list, and/or a copy of the list printed to
This tool implements the first guideline described in
net.jini.loader.pref. In many cases it is sufficient to specify
the roots via the
-proxy option. The
-impl options are used to generate lists for JAR files
in which the roots are not completely defined by the
proxy classes, or for non-service JAR files. Since there is no definitive
set of rules for determining whether a class should be preferred,
the developer should verify the correctness of the generated list.
The following items are discussed below:
To run the tool on Microsoft Windows platforms:java -jar install_dir/lib/preferredlistgen.jar processing_options
java -jar install_dir\lib\preferredlistgen.jar processing_options
Class-Pathattribute, then these JAR files will also be processed recursively. The default behavior is to replace the original JAR file with a new file containing the generated preferred list. If the original target JAR file contained a preferred list, that list is ignored and is replaced by the newly generated list. This option may be specified zero or more times. If multiple
-jaroptions are specified, the first file specified is considered the target JAR file.
Baris a nested class of
Barwould be expressed as
Foo$Bar. The most specific name-expression is used to match an entry. By default, any public class in the JAR file that matches name-expression will be included in the set of roots for dependency analysis. If name-expression is a class name, then that class will be included in the set of roots irregardless of its access modifier. If the
-nonpublicoption is also present, then matching non-public classes will also be included in the set of roots. The
-apioption may be specified zero or more times.
As an example, presuming the class
was included in the target JAR file, then the following would all cause
that class to be included in the public API:
and the last example would also apply to, for instance,-api org/apache/river/example/Foo.class -api org.apache.river.example.Foo -api org/apache/river/example/* -api org/apache/river/example/-
-apioption. If name-expression is a class name or a class JAR entry name, that class will be considered preferred and will not be selected by or included in the dependency analysis even if it was included in the set of roots as a result of processing the
-apioptions. This option may be specified zero or more times.
-apiname-expressions to be included in the set of roots for dependency analysis.
-apioptions may be used to initialize the preferred state of the merged classes.
falsecase will not be generated (except when no single entry is found, in which case a default preferred value of
falseis written). In the event of optimization ties, a default value of false is used.
System.out, even if the list is also placed in an updated JAR file.
Using values from the
-impl options, a
graph is constructed that defines initial preferred values to be inherited by
the target JAR entries as they are loaded into the graph. If there were no
such options specified, all entries from the target JAR file loaded into the
graph initially will be marked as preferred. The classes and resources
identified by the first
-jar option (the target JAR file) are
then loaded into this graph and are assigned their initial preferred
values. The remaining JAR files that include preferred lists are loaded into
the graph and the entries assigned preferred values based on the preferred
list contained in the JAR file being loaded. If a non-target JAR file does
not contain a preferred list, the default behavior is to merge the classes
and resources in the file with those of the target JAR file (for purposes of
dependency analysis only), making them subject to the
-impl options. The
-nomerge option can be used to
override the default behavior, causing all such classes to be assigned a
value of not preferred. The set of root classes is constructed by finding
all of the classes from the target JAR file that are marked as not preferred
in the graph, and by adding all of the public interfaces, or any public
superinterfaces of non-public interfaces implemented by the proxy classes
specified via the
-proxy option. Starting with the root classes,
dependent classes are identified by examining the compiled class file for the
class, finding all of the public and protected fields, methods, constructors,
interfaces, and super classes it references, and then in turn examining those
classes. Any dependent classes found that also exist in the graph will be
marked not preferred, unless that class was explicitly named by a
-impl option. Any root class or dependent class named by a
-impl option retains its original preferred value and no further
dependency analysis is performed for the class. The range of the dependency
analysis is restricted to the set of classes included in the graph.
The tool then processes the graph to find the smallest number of preferred list entries that describes the preferred state of all classes and resources in the graph. The resulting preferred list may be printed or included in a JAR file that replaces the original (first) JAR file.
org.apache.river.reggie.AdminProxyare not identified on the command line because they are parent classes of
java -jar install_dir/lib/preferredlistgen.jar \ -cp install_dir/lib/jsk-platform.jar \ -jar install_dir/lib-dl/reggie-dl.jar \ -jar install_dir/lib-dl/jsk-dl.jar \ -proxy org.apache.river.reggie.ConstrainableRegistrarProxy \ -proxy org.apache.river.reggie.ConstrainableAdminProxy
|Constructor and Description|
Constructor for programmatic access.
|Modifier and Type||Method and Description|
Initialize the dependency graph with a public API entry.
Initialize the dependency graph with a private API entry.
Load JAR files, initialize the dependency graph, and perform the dependency analysis.
Generate the preferred list from the dependency graph.
The command line interface to the tool.
Set the classpath of the classes to include in the analysis.
Set the default value to use for the preferred list.
Set the flag controlling whether non-public classes should be retained in the set of roots used for performing dependency analysis.
Select the behavior for processing non-target JAR files which do not contain preferred lists.
Set the flag controlling whether a preferred list is to be printed.
Set the flag controlling whether a preferred list is to be placed in the target JAR file.
addmethods must be called to supply the argument values. Then
generatePreferredListmust be called to perform the dependency analysis and to generate the preferred list.
public final void setPrint(boolean printResults)
PrintWritersupplied in the call to
null. The default value is
true, print the preferred list
public final void setKeepNonPublicRoots(boolean keepNonPublicRoots)
true, non-public root classes are retained
public final void setMerge(boolean doMerge)
true, the classes contained in these JAR files are merged with the target JAR file for purposes of dependency analysis. The
-apioptions may be used to initialize the preferred state of the merged classes. If
false, the classes in non-target JAR files which do not contain preferred lists are initialized with a preferred state of 'not preferred'. The default behavior corresponds to calling
true, perform the merge
public final void setReplaceJar(boolean replaceJar)
true, update the target JAR file
public final void addJar(String jarName)
jarNameto the list of JAR files to process. The first call identifies the target JAR file. This method must be called at least once.
jarName- the name of the JAR file to add to the set.
public final void addTell(String tellName)
tellNameto the tell list. If a class is identified as not preferred through the dependency analysis, and if that class name is in the tell list, then the source dependency causing the class to be included is printed. This is for debugging purposes.
tellName- the name of the JAR file to add to the tell set.
public final void addImpl(String implName)
implNameidentifies a class or a JAR entry, package, or namespace that is to be considered private and therefore preferred. If
implNameends with ".class", it represents a class whose name is
implNamewithout the ".class" suffix and with each '/' character replaced with a '.'. Otherwise, if
implNameends with "/" or "/*", it represents a directory wildcard matching all entries in the named directory. Otherwise, if
implNameends with "/-", it represents a namespace wildcard that matches all entries in the named directory and all of its subdirectories. Otherwise
implNamerepresents a non-class resource in the JAR file. Alternatively,
implNamemay be expressed directly as a class name. The most specific
implNameis used to match an entry found in the JAR files being analyzed. If
implNameis either of the class name forms, then that class is forced to be preferred and is not included in the public API even it is found by the dependency analysis.
implName- the identifier for the private API entry
implNamedoes not match any of the criteria above.
public final void addApi(String apiName)
apiNameidentifies a class or a JAR entry, package, or namespace that is to be considered public and therefore not preferred. If
apiNameends with ".class", it represents a class whose name is
apiNamewithout the ".class" suffix and with each '/' character replaced with a '.'. Otherwise, if
apiNameends with "/" or "/*", it represents a directory wildcard matching all entries in the named directory. Otherwise, if
apiNameends with "/-", it represents a namespace wildcard that matches all entries in the named directory and all of its subdirectories. Otherwise
apiNamerepresents a non-class resource in the JAR file. Alternatively,
apiNamemay be expressed directly as a class name. The most specific
apiNameis used to match an entry found in the JAR files being analyzed. Any class in the JAR file that matches
apiNamewill be included in the set of roots for dependency analysis. This method may be called zero or more times.
apiName- the identifier for the public API entry
apiNamedoes not match any of the criteria above.
public final void setDefault(boolean def)
def- the default value to use for the list
public final void setClasspath(String path)
path- the classpath for the classes to include in the analysis
public final void addProxy(String proxy)
proxyto the set of proxies used to identify roots. This method may be called zero or more times.
proxy- the name of the proxy class
public void compute() throws IOException
IOException- if an error occurs constructing the class loader or reading any of the JAR files.
IllegalArgumentException- in the following cases:
addJarwas never called or
addJarwas called with a file which does not exist or is a directory
addProxymethod could not be found
public void generatePreferredList(PrintWriter writer) throws IOException
false/truein order of precedence for 'optimization ties') is generated. An explicit default entry is generated only for the default
The preferred list is sorted such that more specific definitions precede less specific definitions; ties are broken with an alphabetic secondary sort.
The preferred list will be placed in the target JAR file unless
setReplaceJar(false) was called. The preferred list will be
writer if it is non-
was called, the preferred list will be written to
PrintWriterto write the preferred list to.
IOException- if an error occurs updating the target JAR file.
public static void main(String args)
args- the command line arguments
Copyright 2007-2013, multiple authors.
Licensed under the Apache License, Version 2.0, see the NOTICE file for attributions.