GigaSpaces XAP 9.5 API

com.sun.jini.tool
Class PreferredListGen

java.lang.Object
  extended by com.sun.jini.tool.PreferredListGen

public class PreferredListGen
extends Object

Tool used to generate the preferred class information for downloadable JAR files in the form of a META-INF/PREFERRED.LIST required for use by the 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:

Running the Tool

To run the tool on UNIX platforms:
 java -jar jsk_install_dir/lib/preferredlistgen.jar processing_options 
 
To run the tool on Microsoft Windows platforms:
 java -jar jsk_install_dir\lib\preferredlistgen.jar processing_options 
 

Note that the options for this tool can be specified in any order, and can be intermixed.

Processing Options

-cp input_classpath
Identifies the classpath for all of the classes that might need to be included in the dependency analysis. Typically this will include all of your application classes, classes from the starter kit, and any other classes on which your classes might depend. It is safe to include more classes than are actually necessary because the tool limits the scope of the preferred list to those classes actually included in the JAR files being analyzed. It is not necessary to include the JAR files being analyzed in the classpath as they will be appended automatically. It is also unnecessary to include any classes that are part of the Java(TM) 2 SDK. The class path should be in the form of a list of directories or JAR files, delimited by a colon (":") on UNIX platforms and a semi-colon (";") on Microsoft Windows platforms. The order of locations in the path does not matter.

-jar file
Identifies a JAR file containing the classes to analyze. If the JAR manifest includes a 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
Identifies the class name of a proxy in the target JAR file. All of the public interfaces implemented by the proxy, and all of the public super interfaces of any non-public interfaces implemented by the proxy, are included in the set of roots for performing dependency analysis. This option may be specified zero or more times.

-api name-expression
This option identifies a class or a JAR entry, package, or namespace that is to be considered public and therefore not preferred. If name-expression ends with ".class", it represents a class whose name is name-expression without the ".class" suffix and with each '/' character replaced with a '.'. Otherwise, if name-expression ends with "/" or "/*", it represents a directory wildcard matching all entries in the named directory. Otherwise, if name-expression ends with "/-", it represents a namespace wildcard that matches all entries in the named directory and all of its subdirectories. Otherwise name-expression represents a non-class resource in the JAR file. Alternatively, name-expression may be expressed directly as a class name. A nested (including inner) class must be expressed as a binary class name; if 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 com.sun.jini.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 com/sun/jini/example/Foo.class
    -api com.sun.jini.example.Foo
    -api com/sun/jini/example/*
    -api com/sun/jini/example/-
 
and the last example would also apply to, for instance, com.sun.jini.example.gui.FooPanel.

-impl name-expression
This option identifies a class or a JAR entry, package, or namespace that is to be considered private and therefore preferred. name-expression is interpreted as described for the -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
This option forces any non-public classes matched by the -api name-expressions to be included in the set of roots for dependency analysis.

-nomerge
Causes the classes in JAR files which do not contain preferred lists to be considered not preferred. If this option is not specified, all classes in JAR files which do not contain preferred lists are merged with the classes supplied by the target JAR file for purposes of dependency analysis; the additional classes are not included in the generated target JAR file. The -impl and -api options may be used to initialize the preferred state of the merged classes.

-default false|true
Specifies the default preferred value to use when generating the preferred list and forces the generation of an explicit default preferred entry in the preferred list. If this option is not provided, the default that produces a list with the fewest entries is used; an explicit entry for the default false case will not be generated. In the event of optimization ties, a default value of false is used.

-noreplace
Inhibits the replacement of the original JAR file with a new updated JAR file. If this option is specified, the preferred list is printed on System.out.

-print
Causes the preferred list to be printed to System.out, even if the list is also placed in an updated JAR file.

-tell classname
Specifies the fully qualified name of a class for which dependency information is desired. This option causes the tool to display information about every class in the dependency graph that references the specified class. If no class references the specified class, it will be identified as a root class. This information is sent to the error stream of the tool, not to the normal output stream. This option can be specified zero or more times. If this option is used, all other output options are ignored, and the normal class output is not produced. This option is useful for debugging.

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.

Examples

The following example generates the preferred list for the codebase JAR file for reggie, replacing the original reggie-dl.jar with a new file containing the preferred list. The reggie implementation includes four proxy classes, however com.sun.jini.reggie.RegistrarProxy and com.sun.jini.reggie.AdminProxy are not identified on the command line because they are parent classes of com.sun.jini.reggie.ConstrainableRegistrarProxy and com.sun.jini.reggie.ConstrainableAdminProxy.

 java -jar jsk_install_dir/lib/preferredlistgen.jar
      -cp jsk_install_dir/lib/jsk-platform.jar
      -jar jsk_install_dir/lib-dl/reggie-dl.jar
      -jar jsk_install_dir/lib-dl/jsk-dl.jar
      -proxy com.sun.jini.reggie.ConstrainableRegistrarProxy 
      -proxy com.sun.jini.reggie.ConstrainableAdminProxy 
 

Author:
Sun Microsystems, Inc.

Constructor Summary
PreferredListGen()
          Constructor for programmatic access.
 
Method Summary
 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.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

PreferredListGen

public PreferredListGen()
Constructor for programmatic access. The public 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.

Method Detail

setPrint

public void setPrint(boolean printResults)
Set the flag controlling whether a preferred list is to be printed. This flag is ignored if the PrintWriter supplied in the call to generatePreferredList is non-null. The default value is false.

Parameters:
printResults - if true, print the preferred list

setKeepNonPublicRoots

public 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. By default, non-public classes are discarded.

Parameters:
keepNonPublicRoots - if true, non-public root classes are retained

setMerge

public void setMerge(boolean doMerge)
Select the behavior for processing non-target JAR files which do not contain preferred lists. If 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).

Parameters:
doMerge - if true, perform the merge

setReplaceJar

public void setReplaceJar(boolean replaceJar)
Set the flag controlling whether a preferred list is to be placed in the target JAR file. The default value is true.

Parameters:
replaceJar - if true, update the target JAR file

addJar

public void addJar(String jarName)
Add 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.

Parameters:
jarName - the name of the JAR file to add to the set.

addTell

public void addTell(String tellName)
Add 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.

Parameters:
tellName - the name of the JAR file to add to the tell set.

addImpl

public void addImpl(String implName)
Initialize the dependency graph with a private API entry. 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.

Parameters:
implName - the identifier for the private API entry
Throws:
IllegalArgumentException - if implName does not match any of the criteria above.

addApi

public void addApi(String apiName)
Initialize the dependency graph with a public API entry. 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.

Parameters:
apiName - the identifier for the public API entry
Throws:
IllegalArgumentException - if apiName does not match any of the criteria above.

setDefault

public void setDefault(boolean def)
Set the default value to use for the preferred list. If this method is not called, the default will be chosen which results in a preferred list with the smallest number of entries. In the event of optimization ties, a default value of false is used.

Parameters:
def - the default value to use for the list

setClasspath

public void setClasspath(String path)
Set the classpath of the classes to include in the analysis. It is not necessary to include the JAR files supplied via calls to the addJar method.

Parameters:
path - the classpath for the classes to include in the analysis

addProxy

public void addProxy(String proxy)
Add proxy to the set of proxies used to identify roots. This method may be called zero or more times.

Parameters:
proxy - the name of the proxy class

compute

public void compute()
             throws IOException
Load JAR files, initialize the dependency graph, and perform the dependency analysis.

Throws:
IOException - if an error occurs constructing the class loader or reading any of the JAR files.
IllegalArgumentException - in the following cases:
  • if addJar was never called or addJar was called with a file which does not exist or is a directory
  • if any proxies supplied via the addProxy method could not be found
  • if any component in the classpath does not exist

generatePreferredList

public void generatePreferredList(PrintWriter writer)
                           throws IOException
Generate the preferred list from the dependency graph. If a default value was specified, the optimal list using that default value is generated. Otherwise, the optimal list among the two possibilities (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.

Parameters:
writer - the PrintWriter to write the preferred list to.
Throws:
IOException - if an error occurs updating the target JAR file.

main

public static void main(String[] args)
The command line interface to the tool. Parses the command line arguments, computes the dependency graph, and generates the preferred list.

Parameters:
args - the command line arguments

GigaSpaces XAP 9.5 API

Copyright © GigaSpaces.