javaclass 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (175) hide show
  1. data/Rakefile +67 -56
  2. data/Readme.txt +42 -39
  3. data/example_task.rb +172 -0
  4. data/examples/check_interface_names.rb +44 -0
  5. data/examples/corpus.rb +19 -0
  6. data/examples/count_classes_in_modules.rb +38 -0
  7. data/examples/cumulative_dependencies.rb +39 -0
  8. data/examples/find_all_imported_types.rb +44 -0
  9. data/examples/find_referenced_modules.rb +53 -0
  10. data/examples/find_unreferenced_classes.rb +65 -0
  11. data/examples/generate_class_lists.rb +67 -43
  12. data/examples/profiler_scratchpad.rb +33 -0
  13. data/examples/simple_usage.rb +42 -0
  14. data/history.txt +29 -7
  15. data/javaclass.gemspec +31 -0
  16. data/lib/javaclass/adder_tree.rb +92 -0
  17. data/lib/javaclass/analyse/dependencies.rb +52 -0
  18. data/lib/javaclass/{metric/metrics.txt → analyse/ideas.txt} +2 -2
  19. data/lib/javaclass/analyse/transitive_dependencies.rb +52 -0
  20. data/lib/javaclass/classfile/access_flag_constants.rb +24 -0
  21. data/lib/javaclass/classfile/access_flags.rb +49 -26
  22. data/lib/javaclass/classfile/class_format_error.rb +37 -0
  23. data/lib/javaclass/classfile/class_magic.rb +16 -8
  24. data/lib/javaclass/classfile/class_version.rb +19 -25
  25. data/lib/javaclass/classfile/constant_pool.rb +110 -45
  26. data/lib/javaclass/classfile/constants/base.rb +33 -12
  27. data/lib/javaclass/classfile/constants/double_reference.rb +55 -41
  28. data/lib/javaclass/classfile/constants/single_reference.rb +29 -21
  29. data/lib/javaclass/classfile/constants/value.rb +43 -33
  30. data/lib/javaclass/classfile/java_class_header.rb +72 -46
  31. data/lib/javaclass/classfile/java_class_header_as_java_name.rb +33 -0
  32. data/lib/javaclass/classfile/java_class_header_shortcuts.rb +19 -0
  33. data/lib/javaclass/classfile/references.rb +21 -19
  34. data/lib/javaclass/classlist/class_entry.rb +26 -27
  35. data/lib/javaclass/classlist/jar_searcher.rb +34 -25
  36. data/lib/javaclass/classlist/list.rb +31 -31
  37. data/lib/javaclass/classlist/package_entry.rb +25 -24
  38. data/lib/javaclass/classpath/any_classpath.rb +48 -0
  39. data/lib/javaclass/classpath/class_not_found_error.rb +20 -0
  40. data/lib/javaclass/classpath/classpaths.txt +2 -2
  41. data/lib/javaclass/classpath/composite_classpath.rb +56 -54
  42. data/lib/javaclass/classpath/convention_classpath.rb +38 -0
  43. data/lib/javaclass/classpath/eclipse_classpath.rb +74 -0
  44. data/lib/javaclass/classpath/factory.rb +65 -0
  45. data/lib/javaclass/classpath/file_classpath.rb +47 -0
  46. data/lib/javaclass/classpath/folder_classpath.rb +42 -44
  47. data/lib/javaclass/classpath/jar_classpath.rb +91 -52
  48. data/lib/javaclass/classpath/java_home_classpath.rb +24 -13
  49. data/lib/javaclass/classpath/maven_classpath.rb +44 -0
  50. data/lib/javaclass/classpath/temporary_unpacker.rb +111 -0
  51. data/lib/javaclass/classpath/tracking_classpath.rb +144 -0
  52. data/lib/javaclass/classscanner/ideas.txt +3 -0
  53. data/lib/javaclass/classscanner/imported_types.rb +29 -0
  54. data/lib/javaclass/classscanner/scanners.rb +29 -0
  55. data/lib/javaclass/delegate_directive.rb +15 -0
  56. data/lib/javaclass/dsl/caching_classpath.rb +38 -0
  57. data/lib/javaclass/dsl/classpath_analysers.rb +27 -0
  58. data/lib/javaclass/dsl/java_name_factory.rb +79 -0
  59. data/lib/javaclass/dsl/loader.rb +42 -0
  60. data/lib/javaclass/dsl/loading_classpath.rb +53 -0
  61. data/lib/javaclass/dsl/mixin.rb +54 -0
  62. data/lib/javaclass/gems/zip_file.rb +154 -0
  63. data/lib/javaclass/java_language.rb +50 -0
  64. data/lib/javaclass/java_name.rb +329 -55
  65. data/lib/javaclass/java_name_scanner.rb +95 -0
  66. data/lib/javaclass/resources/iso_3166_countries.txt +240 -0
  67. data/lib/javaclass/resources/jdk0_packages.txt +6 -0
  68. data/lib/javaclass/resources/jdk1_packages.txt +6 -0
  69. data/lib/javaclass/resources/jdk2_packages.txt +4 -0
  70. data/lib/javaclass/resources/jdk3_packages.txt +6 -0
  71. data/lib/javaclass/resources/jdk4_packages.txt +22 -0
  72. data/lib/javaclass/resources/jdk5_packages.txt +5 -0
  73. data/lib/javaclass/resources/jdk6_packages.txt +7 -0
  74. data/lib/javaclass/resources/jdk7_packages.txt +0 -0
  75. data/lib/javaclass/resources/jdk_packages.txt +53 -0
  76. data/lib/javaclass/resources/reserved_words.txt +50 -0
  77. data/lib/javaclass/string_hexdump.rb +76 -0
  78. data/lib/javaclass/string_ux.rb +21 -10
  79. data/lib/javaclass.rb +16 -41
  80. data/license.txt +28 -0
  81. data/planned.txt +13 -0
  82. data/test/data/Object_102.class +0 -0
  83. data/test/data/Runnable_102.class +0 -0
  84. data/test/data/access_flags/AccessFlagsTestAnnotation.class +0 -0
  85. data/test/data/access_flags/AccessFlagsTestAnnotation.java +3 -0
  86. data/test/data/access_flags/AccessFlagsTestEnum$1.class +0 -0
  87. data/test/data/access_flags/AccessFlagsTestEnum.class +0 -0
  88. data/test/data/access_flags/AccessFlagsTestEnum.java +6 -0
  89. data/test/data/access_flags/AccessFlagsTestInner$1.class +0 -0
  90. data/test/data/access_flags/AccessFlagsTestInner$2.class +0 -0
  91. data/test/data/access_flags/AccessFlagsTestInner.class +0 -0
  92. data/test/data/access_flags/AccessFlagsTestInner.java +13 -0
  93. data/test/data/access_flags/AccessFlagsTestPackage.class +0 -0
  94. data/test/data/access_flags/AccessFlagsTestPackage.java +1 -1
  95. data/test/data/api/packagename/AccessFlagsTestPublic.class +0 -0
  96. data/test/data/class_version/ClassVersionTest17.class +0 -0
  97. data/test/data/class_version/make.bat +6 -2
  98. data/test/data/eclipse_classpath/classes/ClassVersionTest12.class +0 -0
  99. data/test/data/eclipse_classpath/lib/JarClasspathTest.jar +0 -0
  100. data/test/data/eclipse_classpath/test-classes/ClassVersionTest13.class +0 -0
  101. data/test/data/folder_classpath/{JarClasspathTestFolder → classes}/ClassVersionTest10.class +0 -0
  102. data/test/data/folder_classpath/{JarClasspathTestFolder → classes}/package/ClassVersionTest11.class +0 -0
  103. data/test/data/jar_classpath/JarClasspathTest.jar +0 -0
  104. data/test/data/jar_classpath/JarClasspathTest.zip +0 -0
  105. data/test/data/jar_classpath/JarClasspathTestManifest.jar +0 -0
  106. data/test/data/jar_classpath/JarClasspathTestMultiManifest.jar +0 -0
  107. data/test/data/jar_classpath/make.bat +6 -2
  108. data/test/data/jar_searcher/BrokenRunnable_102.class +0 -0
  109. data/test/data/java_home_classpath/jdk118/lib/classes.zip +0 -0
  110. data/test/data/java_name_scanner/META-INF/MANIFEST.MF +12 -0
  111. data/test/data/java_name_scanner/plugin.xml +18 -0
  112. data/test/data/maven_classpath/module/pom.xml +8 -0
  113. data/test/data/maven_classpath/module/target/classes/ClassVersionTest12.class +0 -0
  114. data/test/data/maven_classpath/pom.xml +8 -0
  115. data/test/data/maven_classpath/target/classes/ClassVersionTest10.class +0 -0
  116. data/test/data/maven_classpath/target/test-classes/ClassVersionTest11.class +0 -0
  117. data/test/data/transitive_dependencies/A.class +0 -0
  118. data/test/data/transitive_dependencies/A.java +5 -0
  119. data/test/data/transitive_dependencies/B.class +0 -0
  120. data/test/data/transitive_dependencies/B.java +3 -0
  121. data/test/data/transitive_dependencies/C.class +0 -0
  122. data/test/data/transitive_dependencies/C.java +3 -0
  123. data/test/data/transitive_dependencies/Start.class +0 -0
  124. data/test/data/transitive_dependencies/Start.java +4 -0
  125. data/test/data/transitive_dependencies/make.bat +3 -0
  126. data/test/data/zip_file/commons-math-2.2-broken.zip +0 -0
  127. data/test/data/zip_file/regenerated-with-7zip.zip +0 -0
  128. data/test/data/zip_file/regenerated-with-jar.zip +0 -0
  129. data/test/dot_classpath.rb +33 -0
  130. data/test/logging_folder_classpath.rb +19 -0
  131. data/test/setup.rb +1 -1
  132. data/test/test_access_flags.rb +58 -32
  133. data/test/test_adder_tree.rb +78 -0
  134. data/test/test_any_classpath.rb +39 -0
  135. data/test/test_base.rb +9 -7
  136. data/test/test_caching_classpath.rb +41 -0
  137. data/test/test_class_entry.rb +60 -60
  138. data/test/test_class_magic.rb +31 -0
  139. data/test/test_class_version.rb +25 -25
  140. data/test/test_composite_classpath.rb +22 -23
  141. data/test/test_constant_pool.rb +37 -13
  142. data/test/test_convention_classpath.rb +39 -0
  143. data/test/test_eclipse_classpath.rb +73 -0
  144. data/test/test_factory.rb +61 -0
  145. data/test/test_folder_classpath.rb +26 -10
  146. data/test/test_imported_types.rb +34 -0
  147. data/test/test_jar_classpath.rb +29 -14
  148. data/test/test_jar_searcher.rb +27 -14
  149. data/test/test_java_class_header.rb +22 -10
  150. data/test/test_java_class_header_as_java_name.rb +41 -0
  151. data/test/test_java_home_classpath.rb +17 -11
  152. data/test/test_java_name.rb +204 -64
  153. data/test/test_java_name_factory.rb +52 -0
  154. data/test/test_java_name_scanner.rb +24 -0
  155. data/test/test_javaclass_api.rb +43 -0
  156. data/test/test_list.rb +58 -44
  157. data/test/test_load_directive.rb +34 -0
  158. data/test/test_maven_classpath.rb +46 -0
  159. data/test/test_package_entry.rb +27 -22
  160. data/test/test_references.rb +14 -14
  161. data/test/test_string_hexdump.rb +24 -0
  162. data/test/test_string_ux.rb +18 -106
  163. data/test/test_tracking_classpath.rb +112 -0
  164. data/test/test_transitive_dependencies.rb +31 -0
  165. data/test/test_unpacking_jar_classpath.rb +43 -0
  166. data/test/test_zip_file.rb +33 -0
  167. data/test/ts_all_tests.rb +80 -18
  168. data/thanks.txt +2 -0
  169. metadata +151 -22
  170. data/lib/javaclass/classpath/port_ClassPathEntry.java +0 -202
  171. data/lib/javaclass/classpath/port_ClassPathEntryFactory.java +0 -311
  172. data/lib/javaclass/classpath/port_DirectoryRepository.java +0 -24
  173. data/lib/javaclass/metric/ccd.rb +0 -68
  174. data/lib/javaclass/metric/class_usage.rb +0 -41
  175. data/test/test_javaclass.rb +0 -22
@@ -0,0 +1,44 @@
1
+ # Example usage of the class analysis featuress of JavaClass::ClassScanner and JavaClass::Analyse.
2
+ # After defining a classpath, use dependency analysis to find all used classes of a codebase.
3
+ # This code uses in turn the method <i>imported_3rd_party_types</i> of
4
+ # JavaClass::ClassScanner::ImportedTypes to find all imported classes.
5
+ # Author:: Peter Kofler
6
+ # Copyright:: Copyright (c) 2009, Peter Kofler.
7
+ # License:: {BSD License}[link:/files/license_txt.html]
8
+ #
9
+ # === Steps
10
+
11
+ #--
12
+ # add the lib of this gem to the load path
13
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
14
+ require File.join(File.dirname(__FILE__), 'corpus')
15
+
16
+ location = Corpus[:Lib]
17
+ prod_location = File.join(location, '..', 'classes')
18
+ test_location = File.join(location, 'classes')
19
+ conf_location = location
20
+ #++
21
+ require 'javaclass/dsl/mixin'
22
+
23
+ # 1) create the classpath of production classes
24
+ cp = classpath(prod_location)
25
+
26
+ # 2) remember all types defined on this classpath from JavaClass::Analyse::Dependencies
27
+ prod_classnames = cp.types
28
+
29
+ # 3) collect all dependencies of all classes defined there
30
+ imported_classnames = cp.used_types
31
+
32
+ # 4) also collect all classes referenced from config files, defined in JavaClass::JavaNameScanner
33
+ hardcoded_classnames = scan_config_for_3rd_party_class_names(conf_location)
34
+
35
+ # 5) now we know all classes imported/used by production classes
36
+ puts '---------- used 3rd party types in production'
37
+ used_classnames = (imported_classnames + hardcoded_classnames).uniq.sort - prod_classnames
38
+ puts used_classnames
39
+
40
+ # 6) do the same for test classes, at least org.junit.* should show up here
41
+ test_cp = classpath(test_location)
42
+ puts '---------- used 3rd party types only in tests'
43
+ test_classes = test_cp.external_types - prod_classnames - used_classnames
44
+ puts test_classes
@@ -0,0 +1,53 @@
1
+ # Example usage of JavaClass::Classpath and JavaClass::Classpath::TrackingClasspath:
2
+ # Use the classes of one module and mark all their dependencies. Then find all modules
3
+ # which were not referenced. This list contains *potential* unused libraries (modules).
4
+ # Note that the libraries may still be used by reflection or internal from other libraries.
5
+ # Author:: Peter Kofler
6
+ # Copyright:: Copyright (c) 2009, Peter Kofler.
7
+ # License:: {BSD License}[link:/files/license_txt.html]
8
+ #
9
+ # === Steps
10
+
11
+ #--
12
+ # add the lib of this gem to the load path
13
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
14
+ require File.join(File.dirname(__FILE__), 'corpus')
15
+
16
+ location = Corpus[:HBD]
17
+ location = Corpus[:RCP]
18
+ location = Corpus[:BIA]
19
+
20
+ main_location = File.join(location, 'classes')
21
+ test_location = File.join(location, 'test-classes')
22
+ #++
23
+ require 'javaclass/dsl/mixin'
24
+
25
+ # 1) create a classpath of the main module(s) under test
26
+ main_classpath = classpath("#{main_location};#{test_location}")
27
+ puts "#{main_classpath.count} classes found in main classpath:"
28
+ puts " #{main_classpath.elements.join("\n ")}"
29
+
30
+ # 2) mix in JavaClass::Classpath::TrackingClasspath before creating any new classpaths
31
+ require 'javaclass/classpath/tracking_classpath'
32
+
33
+ # 3) create the (tracking) composite classpath of the given workspace
34
+ cp = workspace(location)
35
+ puts "#{cp.elements.size} classpaths found under the workspace #{location}"
36
+ puts " #{cp.elements.join("\n ")}"
37
+ puts "#{cp.count} classes found in classpaths"
38
+
39
+ # 4) mark all their referenced types as accessed in the workspace
40
+ puts 'mapping referenced classes... (can take several minutes)'
41
+ cp.reset_access
42
+ main_classpath.external_types.each { |clazz| cp.mark_accessed(clazz) }
43
+ puts 'referenced classes mapped'
44
+
45
+ # 5a) now find non accessed modules/libraries (i.e. classpath elements)
46
+ unused = cp.elements.find_all { |clp| clp.jar? && clp.accessed == 0 }
47
+ puts "\n#{unused.size} unused modules found:\n #{unused.join("\n ")}"
48
+
49
+ # 5b) or print the list of classpath elements (e.g. JARs) with their access
50
+ puts "\nlibrary (module path): number of accessed classes"
51
+ puts cp.elements.map { |clp| [clp.to_s, clp.accessed] }.
52
+ sort { |a,b| a[1] <=> b[1] }.
53
+ map { |e| " #{e[0]}: #{e[1]}" }
@@ -0,0 +1,65 @@
1
+ # Advanced example usage of JavaClass::Classpath::TrackingClasspath. Load all
2
+ # classes of an Eclipse workspace. Then mark all referenced classes. In the end
3
+ # report remaining classes as unreferenced. This lists *potential* unused classes.
4
+ # Note that the classes may still be used by reflection.
5
+ # Author:: Peter Kofler
6
+ # Copyright:: Copyright (c) 2009, Peter Kofler.
7
+ # License:: {BSD License}[link:/files/license_txt.html]
8
+ #
9
+ # === Steps
10
+
11
+ #--
12
+ # add the lib of this gem to the load path
13
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
14
+ require File.join(File.dirname(__FILE__), 'corpus')
15
+
16
+ location = Corpus[:RCP]
17
+ package1 = 'com.ibm.arc.sdm'
18
+ package2 = 'pricingTool'
19
+ #++
20
+ require 'javaclass/dsl/mixin'
21
+ require 'javaclass/classpath/tracking_classpath'
22
+
23
+ # speed up loading by skipping non source file classpaths
24
+ Eclipse.skip_lib
25
+
26
+ # 1) create the (tracking) composite classpath of the given workspace
27
+ cp = workspace(location)
28
+ puts "#{cp.elements.size} classpaths found under the workspace #{location}:"
29
+ puts " #{cp.elements.join("\n ")}"
30
+
31
+ # create a filter to limit all operations to the classes of two base packages
32
+ filter = Proc.new { |clazz| clazz.same_or_subpackage_of?(package1) ||
33
+ clazz.same_or_subpackage_of?(package2) }
34
+
35
+ # 2) load all classes in the given packages
36
+ puts 'loading all *filtered* classes... (can take several minutes)'
37
+ classes = cp.values(&filter)
38
+ puts "#{classes.size} classes loaded from classpaths"
39
+
40
+ # 3) mark all referenced types in the given packages as accessed
41
+ cp.reset_access
42
+ classes.map { |clazz| clazz.imported_types }.
43
+ flatten.
44
+ find_all(&filter).
45
+ each { |classname| cp.mark_accessed(classname) }
46
+ puts '*filtered* classes mapped'
47
+
48
+ # 4) also mark all classes referenced from config files (e.g. hardcoded class names)
49
+ hardcoded_classnames = scan_config_for_3rd_party_class_names(location).find_all(&filter)
50
+ puts "#{hardcoded_classnames.size} classes references found in configs"
51
+ hardcoded_classnames.each { |classname| cp.mark_accessed(classname) }
52
+ puts 'hardcoded classes mapped'
53
+
54
+ # 5) mark unit tests (all classes ending in Test) on the test projects (classpath elements ending in .test)
55
+ test_projects = cp.elements.find_all { |cpe| cpe.to_s =~ /\.test\// }
56
+ test_projects.each do |project|
57
+ project.names { |classname| classname =~ /Test(?:Case|Suite|s)?\.class/ }.
58
+ each { |classname| project.mark_accessed(classname) }
59
+ end
60
+ puts 'test classes mapped'
61
+
62
+ # 6) find non accessed classes in specific packages and report them
63
+ unused_classes = classes.find_all { |clazz| cp.accessed(clazz) == 0 }
64
+ report = unused_classes.map { |clazz| "#{clazz.to_classname}" }
65
+ puts "#{report.size} unused classes found:\n #{report.join("\n ")}"
@@ -1,61 +1,85 @@
1
+ # Generate a JavaClass::ClassList, which contains all class
2
+ # names with version numbers when introduced. The list is created
3
+ # iterating all JDKs, opening the RT.jars and loading all classes.
4
+ # Author:: Peter Kofler
5
+ # Copyright:: Copyright (c) 2009, Peter Kofler.
6
+ # License:: {BSD License}[link:/files/license_txt.html]
7
+ #
8
+ # === Usage
9
+
10
+ #--
11
+ # add the lib of this gem to the load path
1
12
  $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
2
- require 'javaclass/classlist/list'
13
+ #++
3
14
  require 'javaclass/classlist/jar_searcher'
4
-
5
- # Generate the full class lists starting from a saved one.
6
- # Author:: Peter Kofler
7
- puts "create full class lists for JDKs (by search and open class)"
15
+ require 'javaclass/classpath/jar_classpath'
16
+ require 'javaclass/classlist/list'
8
17
 
9
18
  # Struct to keep configuration what kind of JDK classes should be searched and added.
10
19
  JDK_CONFIG = Struct.new(:version, :label, :paths)
11
- # Define information about JDK to process one after another.
20
+
21
+ #--
22
+ # Windows 7 configuration for 32bit Sun/Oracle JVMs
23
+ PROGRAMS = 'C:\Program Files (x86)\Java'
12
24
  JDKS = [
13
- JDK_CONFIG.new(0, "1.0.2", ['E:\Develop\Java\Compiler\jdk1.0.2\lib']),
14
- JDK_CONFIG.new(1, "1.1.8-09", ['E:\Develop\Java\Compiler\jdk1.1.8\lib', 'E:\Develop\Java\JDK-1.1\Library\swing-1.1.1\lib']),
15
- JDK_CONFIG.new(2, "1.2.2-13", ['C:\Programme\Java\jdk1.2.2_13\jre\lib', 'C:\Programme\Java\jdk1.2.2_13\lib\dt.jar']),
16
- JDK_CONFIG.new(3, "1.3.1-08", ['C:\Programme\Java\jdk1.3.1_08\jre\lib', 'C:\Programme\Java\jdk1.3.1_08\lib\dt.jar']),
17
- JDK_CONFIG.new(4, "1.4.2-03", ['C:\Programme\Java\jdk1.4.2_03\jre\lib', 'C:\Programme\Java\jdk1.4.2_03\lib\dt.jar']),
18
- JDK_CONFIG.new(5, "1.5.0-07", ['C:\Programme\Java\jdk1.5.0_07\jre\lib', 'C:\Programme\Java\jdk1.5.0_07\lib\dt.jar']),
19
- JDK_CONFIG.new(6, "1.6.0-11", ['C:\Programme\Java\jdk1.6.0_21\jre\lib', 'C:\Programme\Java\jdk1.6.0_21\lib\dt.jar']),
20
- #JDK_CONFIG.new(7, "1.7.0-xx", ['C:\Programme\Java\jdk1.7.0_xx\jre\lib']),
25
+ JDK_CONFIG.new(0, '1.0.2', ['E:\Develop\Java\Compiler\jdk1.0.2\lib']),
26
+ JDK_CONFIG.new(1, '1.1.8-09', ['E:\Develop\Java\Compiler\jdk1.1.8\lib', 'E:\Develop\Java\JDK-1.1\Library\swing-1.1.1\lib']),
27
+ JDK_CONFIG.new(2, '1.2.2-13', [PROGRAMS + '\jdk1.2.2_13\jre\lib', PROGRAMS + '\jdk1.2.2_13\lib\dt.jar']),
28
+ JDK_CONFIG.new(3, '1.3.1-08', [PROGRAMS + '\jdk1.3.1_08\jre\lib', PROGRAMS + '\jdk1.3.1_08\lib\dt.jar']),
29
+ JDK_CONFIG.new(4, '1.4.2-03', [PROGRAMS + '\jdk1.4.2_03\jre\lib', PROGRAMS + '\jdk1.4.2_03\lib\dt.jar']),
30
+ JDK_CONFIG.new(5, '1.5.0-07', [PROGRAMS + '\jdk1.5.0_07\jre\lib', PROGRAMS + '\jdk1.5.0_07\lib\dt.jar']),
31
+ JDK_CONFIG.new(6, '1.6.0-26', [PROGRAMS + '\jdk1.6.0_26\jre\lib', PROGRAMS + '\jdk1.6.0_26\lib\dt.jar']),
32
+ JDK_CONFIG.new(7, '1.7.0', [PROGRAMS + '\jdk1.7.0\jre\lib', PROGRAMS + '\jdk1.7.0\lib\dt.jar']),
21
33
  ]
34
+ #++
35
+ # configuration for some JDKs
36
+ # JDKS = [ JDK_CONFIG.new(...), ... ]
22
37
 
23
- BASE_NAME = 'fullClassList'
24
-
25
- # Create a new list
26
- @list = JavaClass::ClassList::List.new
27
-
28
- # load already good list if we do not start with JDK 1.0
29
- if JDKS[0].version > 0
30
- old_version = JDKS[0].version-1
31
- old_class_list_name = Dir["./#{BASE_NAME}?#{old_version}?.txt"].first
32
- if FileTest.exist?(old_class_list_name)
33
- puts "loading #{old_version}"
34
- IO.readlines(old_class_list_name).each {|line| @list.parse_line(line, old_version) }
35
- end
36
- end
38
+ # 1) create a JavaClass::ClassList::JarSearcher
39
+ JavaClass.unpack_jars!(:unpack)
40
+ searcher = JavaClass::ClassList::JarSearcher.new
37
41
 
38
- # init the searcher
39
- @searcher = JavaClass::ClassList::JarSearcher.new
40
- @searcher.filters = %w[sun/ sunw/ com/sun/ netscape/ COM/rsa/ quicktime/ com/apple/mrj/macos/carbon/ org/jcp/xml/dsig/internal/]
42
+ # 2) filter out unwanted classes, e.g. vendor classes
43
+ searcher.filters = %w[sun/ sunw/ com/oracle/ com/sun/ netscape/ COM/rsa/
44
+ quicktime/ com/apple/mrj/macos/carbon/ org/jcp/xml/dsig/internal/]
45
+ #--
41
46
  # netscape ... applet js security [2]
42
47
  # COM/rsa/ ... jsafe [4]
43
48
  # quicktime ... quicktime [5]
44
49
  # org/jcp/xml/dsig/internal ... xml dsig [6]
50
+ # com/oracle/ ... com.oracle.net.Sdp [7]
51
+
52
+ Dir.mkdir './ClassLists' unless File.exist? './ClassLists'
53
+ #++
45
54
 
46
- #Dir.mkdir './ClassLists' unless File.exist? './ClassLists'
55
+ # 3) create a new JavaClass::ClassList::List to contain the classes
56
+ list = JavaClass::ClassList::List.new
47
57
 
48
- # Work on all lists defined in +JDK+ and yield the block with the jdk label and the class list.
58
+ #--
59
+ # load an already good list if we do not start with JDK 1.0
60
+ if JDKS[0].version > 0
61
+ full_class_list_version = JDKS[0].version - 1
62
+ full_class_list = "fullClassList1#{full_class_list_version}0.txt"
63
+ IO.readlines(full_class_list).each {|line| list.parse_line(line, full_class_list_version) }
64
+ puts "loaded full class list #{full_class_list} with versions #{list.version}"
65
+ end
66
+ #++
67
+
68
+ # Work on all lists defined in +JDKS+, add to the list and write list files.
49
69
  JDKS.each do |conf|
50
- puts "processing #{conf.version}"
51
- conf.paths.each { |p| @list = @searcher.compile_list(conf.version, p, @list) }
52
-
53
- #basename = "jdk#{conf.label.gsub(/\./, '')}"
54
- #File.open("./ClassLists/#{basename}_new_package_classes.txt", "w") { |f| f.print @list.old_access_list.collect{|m| m.sub(/\s.*$/, '')} }
55
- #File.open("./ClassLists/#{basename}_all_classes.txt", "w") { |f| f.print @list.plain_class_list }
56
- #File.open("./ClassLists/#{basename}_all_public_classes.txt", "w") { |f| f.print @list.plain_class_list { |c| c.public? } }
57
- #File.open("./ClassLists/#{basename}_new_public_classes.txt", "w") { |f| f.print @list.plain_class_list { |c| c.public? and c.version.first == conf.version } }
58
-
70
+ # 4) iterate JARs and compile a list
71
+ conf.paths.each { |p| list = searcher.compile_list(conf.version, p, list) }
72
+
73
+ # 5) save various kind of lists
74
+ basename = "./ClassLists/jdk#{conf.label.gsub(/\./, '')}"
75
+ File.open("#{basename}_new_package_classes.txt", "w") { |f| f.print list.old_access_list.collect{|m| m.sub(/\s.*$/, '')} }
76
+ File.open("#{basename}_all_classes.txt", "w") { |f| f.print list.plain_class_list }
77
+ File.open("#{basename}_all_packages.txt", "w") { |f| f.print list.to_s }
78
+ File.open("#{basename}_all_public_classes.txt", "w") { |f| f.print list.plain_class_list { |c| c.public? } }
79
+ File.open("#{basename}_new_public_classes.txt", "w") { |f| f.print list.plain_class_list { |c| c.public? and c.version.first == conf.version } }
80
+
59
81
  baseversion = conf.label.gsub(/\.|-.+$/, '')
60
- File.open("./#{BASE_NAME}#{baseversion}.txt", "w") { |f| f.print @list.full_class_list }
82
+ File.open("./fullClassList#{baseversion}.txt", "w") { |f| f.print list.full_class_list }
83
+
84
+ puts "processed #{conf.label}"
61
85
  end
@@ -0,0 +1,33 @@
1
+ # :nodoc:
2
+ # Scratchpad script for profiler execution.
3
+
4
+ require 'ruby-prof'
5
+
6
+ # add the lib of this gem to the load path
7
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
8
+ require 'javaclass/dsl/mixin'
9
+ require File.join(File.dirname(__FILE__), 'corpus')
10
+
11
+ location = File.join(Corpus[:BIA], 'classes')
12
+
13
+ # 1) create a classpath of the given workspace
14
+ #RubyProf.start
15
+ cp = classpath(location)
16
+ puts "#{cp.elements.size} classpaths found under the workspace #{location}:\n #{cp.elements.join("\n ")}"
17
+ puts "#{cp.count} classes found in classpaths"
18
+ #result = RubyProf.stop
19
+
20
+ # 2) load all classes
21
+ RubyProf.start
22
+ cp.values
23
+ result = RubyProf.stop
24
+
25
+ # 3) iterate all constant pool entries
26
+ #RubyProf.start
27
+ # workspace.external_types
28
+ #result = RubyProf.stop
29
+
30
+ # Print a flat profile to text
31
+ printer = RubyProf::GraphPrinter.new(result)
32
+ # printer = RubyProf::FlatPrinter.new(result)
33
+ printer.print(STDOUT)
@@ -0,0 +1,42 @@
1
+ # Example of basic usage of JavaClass to load and inspect class files.
2
+ # Author:: Peter Kofler
3
+ # Copyright:: Copyright (c) 2009, Peter Kofler.
4
+ # License:: {BSD License}[link:/files/license_txt.html]
5
+ #
6
+ # === Usage
7
+
8
+ #--
9
+ # add the lib of this gem to the load path
10
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
11
+ #++
12
+ # 1) require the basic module
13
+ require 'javaclass'
14
+
15
+ # 2a) load a class directly from the file system
16
+ clazz = JavaClass.load_fs('./test/data/access_flags/AccessFlagsTestPublic.class')
17
+
18
+ # 2b) or get a class from the system classpath which needs _JAVA_HOME_ to be set
19
+ cp = JavaClass.environment_classpath
20
+ puts cp.includes?('java/lang/String.class') # => 1 (true)
21
+
22
+ # 2c) or look up the class from some JavaClass::Classpath by its Java qualified name
23
+ cp = JavaClass.classpath('./test/data/access_flags')
24
+ puts cp.includes?('AccessFlagsTestPublic') # => 1 (true)
25
+ clazz = JavaClass.load_cp('AccessFlagsTestPublic', cp)
26
+
27
+ # 3) then retrieve low level information about the class
28
+ puts clazz.version # => "50.0"
29
+ puts clazz.constant_pool.items[1] # => "packagename/AccessFlagsTestPublic"
30
+ puts clazz.access_flags.public? # => true
31
+ puts clazz.access_flags.final? # => false
32
+ puts clazz.this_class # => "packagename/AccessFlagsTestPublic"
33
+ puts clazz.super_class # => "java/lang/Object"
34
+ puts clazz.super_class.to_classname # => "java.lang.Object"
35
+ puts clazz.references.referenced_methods[0] # => "java/lang/Object.<init>:()V"
36
+ puts clazz.interfaces # => []
37
+
38
+ # Returned class names are not just Strings, but JavaClass::JavaQualifiedName
39
+ puts clazz.this_class.to_java_file # => "packagename/AccessFlagsTestPublic.java"
40
+ puts clazz.this_class.full_name # => "packagename.AccessFlagsTestPublic"
41
+ puts clazz.this_class.package # => "packagename"
42
+ puts clazz.this_class.simple_name # => "AccessFlagsTestPublic"
data/history.txt CHANGED
@@ -1,9 +1,31 @@
1
+ === 0.0.4 19/12/2011
2
+
3
+ * convert examples to RDOC using example_task
4
+ * added transitive dependency trees from references
5
+ * patched the rubyzip for invalid flags found in some JARs
6
+ * add some examples
7
+ * fixed generate_class_lists.rb
8
+ * finish first version of DSL with loading/values
9
+ * added Eclipse project aware classpath
10
+ * added Maven aware classpath
11
+ * added ZipFile abstraction over rubyzip gem
12
+ * added class scanning "framework" and imported types Scanners
13
+ * added CachingClasspath
14
+ * added usage of system 7za/unzip (if available) which unpack much faster
15
+ * added option to unpack JARs for faster access later
16
+ * added support for Java Enum and Annotations
17
+ * added DSL like shortcuts for java.* and javax.* package and class names.
18
+ * added interfaces implemented by the class
19
+ * fixed string ux problem in Ruby 1.9
20
+ * replaced leading 0 in exponent of float/double because of Linux printf
21
+ * split Gemspec from Rakefile as proposed by Yeguda Katz
22
+
1
23
  === 0.0.3 02/10/2010
2
24
 
3
25
  * integrated ClassList from another project as first analyser
4
- * add JavaName to all class names that are returned
5
- * fix links in RDoc, update documentation
6
- * move classes into submodules for classpath, classfile, etc.
26
+ * added abstraction of Java names to all class names that are returned
27
+ * fixed links in RDoc, update documentation
28
+ * moved classes into submodules for classpath, classfile, etc.
7
29
  * migrated to Google Code and Mercurial repository
8
30
  * added access flag $1000
9
31
  * added references to used classes
@@ -14,10 +36,10 @@
14
36
  * refactored code to smaller objects for version and constant pool
15
37
  * fixed float and double constant pool items
16
38
  * added tests
17
- * continued implementation with class names and references
39
+ * added implementation with class name and references of a class file
18
40
 
19
41
  === 0.0.1 01/03/2009
20
-
21
- * initial version extracted from ClassList project
42
+
43
+ * extracted initial version of javaclass-rb from ClassList project
22
44
  * reads the class version and package/public flag of a class
23
- * understands the constant pool but does not use it
45
+ * understands the constant pool of class file but does not use it
data/javaclass.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ GEM_NAME = 'javaclass'
2
+ GOOGLE_PROJECT = "#{GEM_NAME}-rb"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.version = '0.0.4'
6
+ s.name = GEM_NAME
7
+ s.rubyforge_project = 'javaclass' # old, just redirects
8
+ s.summary = 'A parser and disassembler for Java class files'
9
+ s.description = 'Provides access to the package, protected, and public fields and methods of the classes passed to it together with a list of all outgoing references.'
10
+ s.license = 'BSD'
11
+ s.homepage = "http://code.google.com/p/#{GOOGLE_PROJECT}/"
12
+ s.author = 'Peter Kofler'
13
+ s.email = 'peter dot kofler at code minus cop dot org'
14
+ s.date = Time::gm(2011, 12, 19)
15
+
16
+ s.files = Dir.glob('*.txt') + Dir.glob('{lib,test,examples}/**/*') + ['javaclass.gemspec', 'Rakefile', 'example_task.rb']
17
+ s.test_files = Dir.glob('test/**/test_*.rb')
18
+ s.require_path = 'lib'
19
+ s.add_dependency('rubyzip', '>= 0.9.1')
20
+ s.required_ruby_version = '>= 1.8.6'
21
+ s.required_rubygems_version = nil if s.respond_to? :required_rubygems_version=
22
+ s.platform = Gem::Platform::RUBY
23
+ s.add_development_dependency('rake', '>= 0.8.4')
24
+ s.add_development_dependency('rcov', '>= 0.8.1.2')
25
+ # s.add_development_dependency('ZenTest', '>= 4.4.0')
26
+
27
+ s.has_rdoc = true
28
+ s.extra_rdoc_files = Dir.glob('*.txt')
29
+ s.rdoc_options << '--title' << "#{s.name}-#{s.version} Documentation" <<
30
+ '--main' << 'Readme.txt'
31
+ end
@@ -0,0 +1,92 @@
1
+ # A node in the AdderTree.
2
+ # Author:: Peter Kofler
3
+ class AdderTreeNode
4
+
5
+ attr_reader :parent
6
+ attr_reader :data
7
+
8
+ def initialize(data, parent)
9
+ @data = data
10
+ @parent = parent
11
+ @children = []
12
+ end
13
+
14
+ def children
15
+ @children.dup
16
+ end
17
+
18
+ def add(o)
19
+ node = AdderTreeNode.new(o, self)
20
+ @children << node
21
+ node
22
+ end
23
+
24
+ def contain?(o)
25
+ if @data == o
26
+ self
27
+ else
28
+ @children.find { |child| child.contain?(o) }
29
+ end
30
+ end
31
+
32
+ def level
33
+ @parent.level + 1
34
+ end
35
+
36
+ def root
37
+ @parent.root
38
+ end
39
+
40
+ # Return the number of nodes this this (sub-)tree.
41
+ def size
42
+ @children.inject(1) { |sum, child| sum + child.size }
43
+ end
44
+
45
+ def levels
46
+ ( [1] + @children.map { |child| 1 + child.levels } ).max
47
+ end
48
+
49
+ # Return an array of all children. Each child has its own array. For example
50
+ # tree = AdderTree.new(0)
51
+ # tree.add(1)
52
+ # tree.to_a # => [0, [1]]
53
+ def to_a
54
+ if @children.size > 0
55
+ sublist = []
56
+ @children.each { |child| child.to_a.each { |c| sublist << c } }
57
+ [data, sublist]
58
+ else
59
+ [data]
60
+ end
61
+ end
62
+
63
+ # Prints the tree to the console. Each level of the tree is intended by a blank.
64
+ def debug_print
65
+ puts ' ' * level + data
66
+ @children.each { |child| child.debug_print }
67
+ end
68
+
69
+ end
70
+
71
+ # The root node of the adder tree. The "adder tree" is a simple add-only tree.
72
+ # Once the tree is build it can't be changed. Only new elements can be added.
73
+ # The tree's main functionality is defined in AdderTreeNode.
74
+ # Author:: Peter Kofler
75
+ class AdderTree < AdderTreeNode
76
+
77
+ attr_reader :parent
78
+ attr_reader :data
79
+
80
+ def initialize(data)
81
+ super(data, nil)
82
+ end
83
+
84
+ def level
85
+ 0
86
+ end
87
+
88
+ def root
89
+ self
90
+ end
91
+
92
+ end
@@ -0,0 +1,52 @@
1
+ module JavaClass
2
+
3
+ # The module Analyse is for separating namespaces. It contains various methods
4
+ # to analyse classes accross a whole whole code bases (Classpath). The functionality
5
+ # of all analysers is collected in Dsl::ClasspathAnalysers.
6
+ # Author:: Peter Kofler
7
+ module Analyse
8
+
9
+ # Analyser to get dependencies of a whole Classpath (to be mixed into Dsl::LoadingClasspath).
10
+ # For an example see
11
+ # {how to list all imported types}[link:/files/lib/generated/examples/find_all_imported_types_txt.html].
12
+ # Author:: Peter Kofler
13
+ module Dependencies
14
+
15
+ # Return all types in this classpath. An additional block is used as _filter_ on class names.
16
+ # Returns a list of JavaQualifiedName. Requires a method _names_ in the base class.
17
+ def types(&filter)
18
+ names(&filter).collect { |c| c.to_classname }.sort
19
+ end
20
+
21
+ # Determine all imported types from all classes in this classpath together with count of imports.
22
+ # An additional block is used as _filter_ on class names. Requires a method _values_ in the base class.
23
+ def used_types_map(&filter)
24
+ type_map = Hash.new(0) # class_name (JavaQualifiedName) => cnt
25
+ values(&filter).collect { |clazz| clazz.imported_3rd_party_types }.flatten.each do |type|
26
+
27
+ # hash keys need to be frozen to keep state
28
+ if !type_map.include?(type)
29
+ type = type.freeze
30
+ end
31
+
32
+ type_map[type] += 1
33
+ end
34
+ type_map
35
+ end
36
+
37
+ # Determine all imported types from all classes in this classpath.
38
+ # An additional block is used as _filter_ on class names.
39
+ def used_types(&filter)
40
+ used_types_map(&filter).keys.sort
41
+ end
42
+
43
+ # Determine all foreign imported types from all classes in this classpath.
44
+ # An additional block is used as _filter_ on class names.
45
+ def external_types(&filter)
46
+ used_types(&filter) - types(&filter)
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+ end
@@ -1,4 +1,4 @@
1
- === Metrics
1
+ === Metrics/Analysis across a whole classpath
2
2
 
3
3
  * "metric" if all referencing classes of a class is another package, propose moving it there.
4
4
  * "Greed Detector"
@@ -6,7 +6,7 @@
6
6
  * which signatures are called how often
7
7
  * maybe move current method there?
8
8
  * CRSS Metric
9
- * CCD
9
+ * CCD: lazy init, classpath sits inside the analyser and works recursively through all elements
10
10
 
11
11
  * {Chidamber and Kemerer Java Metrics (ckjm)}[http://www.spinellis.gr/sw/ckjm/]
12
12
  * {The CRSS Metric for Package Design Quality}[http://crpit.com/confpapers/CRPITV62Melton2.pdf]
@@ -0,0 +1,52 @@
1
+ require 'javaclass/adder_tree'
2
+
3
+ module JavaClass
4
+ module Analyse
5
+
6
+ # Transitive dependency analysis to be mixed into Dsl::LoadingClasspath. For an example see
7
+ # {how to get cumulative dependencies of a class}[link:/files/lib/generated/examples/cumulative_dependencies_txt.html].
8
+ # For plain dependencies of a Classpath see Dependencies.
9
+ # Author:: Peter Kofler
10
+ module TransitiveDependencies
11
+
12
+ # Creates the tree of all transitive dependencies of _classname_ where every dependency is only
13
+ # listed once at its first occurence. It returns an AdderTree containing all found dependencies.
14
+ # An additional block is used as _filter_ on class names to work with, e.g. the main classes.
15
+ # Requires methods <i>includes?</i> and _load_ in the base class.
16
+ def transitive_dependency_tree(classname, tree=nil, &filter)
17
+ return if block_given? && !filter.call(classname)
18
+ return if tree && tree.root.contain?(classname)
19
+
20
+ if tree
21
+ tree = tree.add(classname.to_classname)
22
+ else
23
+ tree = AdderTree.new(classname.to_classname)
24
+ end
25
+
26
+ if includes?(classname)
27
+ load(classname).imported_3rd_party_types.each do |classname|
28
+ transitive_dependency_tree(classname, tree, &filter)
29
+ end
30
+ end
31
+
32
+ tree
33
+ end
34
+
35
+ # Creates the tree of all transitive dependencies of the Java _package_ where every dependency is only
36
+ # listed once at its first occurence. It returns an AdderTree containing all found dependencies.
37
+ # An additional block is used as _filter_ on class names to work with, e.g. the main classes.
38
+ # Requires a method _names_ in the base class.
39
+ def transitive_dependencies_package(package, &filter)
40
+ tree = AdderTree.new(package)
41
+
42
+ names { |classname| classname.same_or_subpackage_of?(package) }.each do |classname|
43
+ transitive_dependency_tree(classname, tree, &filter)
44
+ end
45
+
46
+ tree
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+ end