1. /*
  2. * Copyright 2003-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.attributes.compiler;
  17. import java.io.BufferedInputStream;
  18. import java.io.BufferedOutputStream;
  19. import java.io.File;
  20. import java.io.FileOutputStream;
  21. import java.io.InputStream;
  22. import java.io.PrintWriter;
  23. import java.io.PrintStream;
  24. import java.net.URL;
  25. import java.net.URLClassLoader;
  26. import java.util.ArrayList;
  27. import java.util.Collection;
  28. import java.util.Enumeration;
  29. import java.util.HashMap;
  30. import java.util.HashSet;
  31. import java.util.Iterator;
  32. import java.util.List;
  33. import java.util.jar.JarFile;
  34. import java.util.jar.JarEntry;
  35. import java.util.jar.JarOutputStream;
  36. import org.apache.commons.attributes.AttributeRepositoryClass;
  37. import org.apache.commons.attributes.Attributes;
  38. import org.apache.commons.attributes.AttributeUtil;
  39. import org.apache.commons.attributes.Indexed;
  40. import org.apache.tools.ant.AntClassLoader;
  41. import org.apache.tools.ant.BuildException;
  42. import org.apache.tools.ant.Task;
  43. import org.apache.tools.ant.types.FileSet;
  44. import org.apache.tools.ant.types.Path;
  45. /**
  46. * Ant task to compile attribute indexes. Usage:
  47. *
  48. * <pre><code>
  49. * <taskdef resource="org/apache/commons/attributes/anttasks.properties"/>
  50. *
  51. * <attribute-indexer jarFile="myclasses.jar">
  52. * <classpath>
  53. * ...
  54. * </classpath>
  55. * </attribute-indexer>
  56. * </code></pre>
  57. *
  58. * The task will inspect the classes in the given jar and add a <tt>META-INF/attrs.index</tt>
  59. * file to it, which contains the index information. The classpath element is required and
  60. * must contain all dependencies for the attributes used.
  61. */
  62. public class AttributeIndexer extends Task {
  63. private File jarFile;
  64. private List classes = new ArrayList ();
  65. private Path classPath;
  66. private File baseName;
  67. private boolean inMaven = false;
  68. private final static String INDEX_FILENAME = "META-INF/attrs.index";
  69. public AttributeIndexer () {
  70. }
  71. public void setJarfile (File jarFile) {
  72. this.jarFile = jarFile;
  73. }
  74. public void setBaseName (File baseName) {
  75. inMaven = true;
  76. this.baseName = baseName;
  77. }
  78. public Path createClasspath () {
  79. this.classPath = new Path(project);
  80. return classPath;
  81. }
  82. private static final String SUFFIX = "$__attributeRepository.class";
  83. protected void copyEntry (JarFile jar, JarEntry entry, JarOutputStream outputStream) throws Exception {
  84. outputStream.putNextEntry (entry);
  85. if (!entry.isDirectory ()) {
  86. InputStream is = new BufferedInputStream (jar.getInputStream (entry));
  87. try {
  88. byte[] buffer = new byte[16384];
  89. while (true) {
  90. int numRead = is.read (buffer, 0, 16384);
  91. if (numRead == 0 || numRead == -1) {
  92. break;
  93. }
  94. outputStream.write (buffer, 0, numRead);
  95. }
  96. } finally {
  97. is.close ();
  98. }
  99. }
  100. }
  101. protected void findJarFile () throws BuildException {
  102. File[] allFiles = baseName.getParentFile ().listFiles ();
  103. if (allFiles == null) {
  104. throw new BuildException ("Unable to find any file with base name " + baseName.getName ()
  105. + " in " + baseName.getParentFile ().getPath ());
  106. }
  107. long newestDate = 0;
  108. for (int i = 0; i < allFiles.length; i++) {
  109. String name = allFiles[i].getName ();
  110. if (name.startsWith (baseName.getName ()) && name.endsWith (".jar") &&
  111. allFiles[i].lastModified () > newestDate) {
  112. jarFile = allFiles[i];
  113. newestDate = allFiles[i].lastModified ();
  114. }
  115. }
  116. if (jarFile == null) {
  117. throw new BuildException ("Unable to find any file with base name " + baseName.getName ()
  118. + " in " + baseName.getParentFile ().getPath ());
  119. }
  120. }
  121. public void execute () throws BuildException {
  122. if (inMaven) {
  123. findJarFile ();
  124. }
  125. if (!jarFile.exists ()) {
  126. log ("Can't find " + jarFile.getPath ());
  127. return;
  128. }
  129. try {
  130. log ("Creating attribute index for " + jarFile.getPath ());
  131. JarFile jar = new JarFile (jarFile);
  132. File newJarFile = new File (jarFile.getPath () + ".new");
  133. JarOutputStream output = new JarOutputStream (new FileOutputStream (newJarFile));
  134. try {
  135. Enumeration enum = jar.entries ();
  136. while (enum.hasMoreElements ()) {
  137. JarEntry entry = (JarEntry) enum.nextElement ();
  138. if (!entry.isDirectory ()) {
  139. String className = entry.getName ();
  140. if (className.endsWith (SUFFIX)) {
  141. className = className.replace ('/', '.').replace ('\\', '.').substring (0, className.length () - SUFFIX.length ());
  142. classes.add (className);
  143. }
  144. }
  145. if (!entry.getName ().equals (INDEX_FILENAME)) {
  146. copyEntry (jar, entry, output);
  147. }
  148. }
  149. output.putNextEntry (new JarEntry (INDEX_FILENAME));
  150. Iterator attrs = classes.iterator ();
  151. while (attrs.hasNext ()) {
  152. String className = (String) attrs.next ();
  153. output.write (("Class: " + className + "\n").getBytes ());
  154. }
  155. } finally {
  156. output.close ();
  157. jar.close ();
  158. }
  159. jarFile.delete ();
  160. newJarFile.renameTo (jarFile);
  161. } catch (Exception e) {
  162. e.printStackTrace ();
  163. throw new BuildException (e.toString ());
  164. }
  165. }
  166. }