public class PreferredListGen extends Object
net.jini.loader.pref.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:
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/-
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
-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 © 2016–2018. All rights reserved.