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 System.out.
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 -api and
-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
Note that the options for this tool can be specified in any order, and can be intermixed.
-cp input_classpath
-jar file
Class-Path attribute, 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 -jar options are specified, the
first file specified is considered the target JAR file.
-proxy classname
-api name-expression
Bar is a nested class of Foo, then
Bar would 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
-nonpublic option is also present, then matching non-public
classes will also be included in the set of roots. The -api
option may be specified zero or more times.
As an example, presuming the class org.apache.river.example.Foo
was included in the target JAR file, then the following would all cause
that class to be included in the public API:
-api org/apache/river/example/Foo.class
-api org.apache.river.example.Foo
-api org/apache/river/example/*
-api org/apache/river/example/-
and the last example would also apply to, for instance,
org.apache.river.example.gui.FooPanel.
-impl name-expression
-api option. 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 -proxy and
-api options. This option may be specified zero or more times.
-nonpublic
-api name-expressions to be included in the set of
roots for dependency analysis.
-nomerge
-impl and -api options may be used to initialize
the preferred state of the merged classes.
-default false|true
false case will not be generated (except when no
single entry is found, in which case a default preferred value of
false is written). In the event of optimization ties, a default
value of false is used.
-noreplace
System.out.
-print
System.out, even if
the list is also placed in an updated JAR file.
-tell classname
Using values from the -api and -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 -api and
-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.RegistrarProxy and
org.apache.river.reggie.AdminProxy are not identified on the command
line because they are parent classes of
org.apache.river.reggie.ConstrainableRegistrarProxy and
org.apache.river.reggie.ConstrainableAdminProxy.
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 |
|---|
PreferredListGen()
Constructor for programmatic access.
|
| Modifier and Type | Method and Description |
|---|---|
void |
addApi(String apiName)
Initialize the dependency graph with a public API entry.
|
void |
addImpl(String implName)
Initialize the dependency graph with a private API entry.
|
void |
addJar(String jarName)
Add
jarName to the list of JAR files to process. |
void |
addProxy(String proxy)
Add
proxy to the set of proxies used to identify
roots. |
void |
addTell(String tellName)
Add
tellName to the tell list. |
void |
compute()
Load JAR files, initialize the dependency graph, and perform the
dependency analysis.
|
void |
generatePreferredList(PrintWriter writer)
Generate the preferred list from the dependency graph.
|
static void |
main(String[] args)
The command line interface to the tool.
|
void |
setClasspath(String path)
Set the classpath of the classes to include in the analysis.
|
void |
setDefault(boolean def)
Set the default value to use for the preferred list.
|
void |
setKeepNonPublicRoots(boolean keepNonPublicRoots)
Set the flag controlling whether non-public classes should be retained
in the set of roots used for performing dependency analysis.
|
void |
setMerge(boolean doMerge)
Select the behavior for processing non-target JAR files which do not
contain preferred lists.
|
void |
setPrint(boolean printResults)
Set the flag controlling whether a preferred list is to be printed.
|
void |
setReplaceJar(boolean replaceJar)
Set the flag controlling whether a preferred list is to be placed
in the target JAR file.
|
public PreferredListGen()
set and
add methods must be called to supply the argument
values. Then compute and generatePreferredList
must be called to perform the dependency analysis and to generate the
preferred list.public final void setPrint(boolean printResults)
PrintWriter supplied in
the call to generatePreferredList is non-null.
The default value is false.printResults - if true, print the preferred listpublic final void setKeepNonPublicRoots(boolean keepNonPublicRoots)
keepNonPublicRoots - if true, non-public root classes
are retainedpublic final void setMerge(boolean doMerge)
doMerge is true, the
classes contained in these JAR files are merged with the target JAR
file for purposes of dependency analysis. The -impl and
-api options may be used to initialize the preferred state
of the merged classes. If doMerge is 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 setMerge(true).doMerge - if true, perform the mergepublic final void setReplaceJar(boolean replaceJar)
true.replaceJar - if true, update the target JAR filepublic final void addJar(String jarName)
jarName to 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)
tellName to 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)
implName identifies a class or a JAR entry, package, or
namespace that is to be considered private and therefore preferred. If
implName ends with ".class", it represents a class whose
name is implName without the ".class" suffix and with each
'/' character replaced with a '.'. Otherwise, if implName
ends with "/" or "/*", it represents a directory wildcard matching all
entries in the named directory. Otherwise, if implName ends
with "/-", it represents a namespace wildcard that matches all entries in
the named directory and all of its subdirectories. Otherwise
implName represents a non-class resource in the JAR
file. Alternatively, implName may be expressed directly as a
class name. The most specific implName is used to match an
entry found in the JAR files being analyzed. If implName is
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 entryIllegalArgumentException - if implName does not match
any of the criteria above.public final void addApi(String apiName)
apiName identifies a class or a JAR entry, package, or
namespace that is to be considered public and therefore not
preferred. If apiName ends with ".class", it represents a
class whose name is apiName without the ".class" suffix and
with each '/' character replaced with a '.'. Otherwise, if
apiName ends with "/" or "/*", it represents a directory
wildcard matching all entries in the named directory. Otherwise, if
apiName ends with "/-", it represents a namespace wildcard
that matches all entries in the named directory and all of its
subdirectories. Otherwise apiName represents a non-class
resource in the JAR file. Alternatively, apiName may be
expressed directly as a class name. The most specific
apiName is used to match an entry found in the JAR files
being analyzed. Any class in the JAR file that matches
apiName will 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 entryIllegalArgumentException - if apiName does not match
any of the criteria above.public final void setDefault(boolean def)
false is used.def - the default value to use for the listpublic final void setClasspath(String path)
addJar method.path - the classpath for the classes to include in the analysispublic final void addProxy(String proxy)
proxy to the set of proxies used to identify
roots. This method may be called zero or more times.proxy - the name of the proxy classpublic 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:
addJar was never
called or addJar was called with a file which
does not exist or is a directory
addProxy
method could not be found
public void generatePreferredList(PrintWriter writer) throws IOException
false/true in order of precedence for 'optimization ties')
is generated. An explicit default entry is generated only for the
default true case.
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
written to writer if it is non-null. If
writer is null and setPrint(true)
was called, the preferred list will be written to
System.out.
writer - the PrintWriter to 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 argumentsCopyright 2007-2013, multiple authors.
Licensed under the Apache License, Version 2.0, see the NOTICE file for attributions.