1
2
3
4
5
6
7
8 package org.codehaus.metaclass.io;
9
10 import java.io.File;
11 import java.io.FileInputStream;
12 import java.io.FileOutputStream;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.io.OutputStream;
16 import org.objectweb.asm.ClassReader;
17 import org.objectweb.asm.ClassWriter;
18 import org.codehaus.metaclass.introspector.MetaClassException;
19 import org.codehaus.metaclass.model.ClassDescriptor;
20
21 /***
22 * Utility class to do IO on descriptors stored in .class files. Uses the ASM
23 * toolkit for .class reading and writing.
24 *
25 * @author Peter Donald
26 * @version $Revision: 1.1 $ $Date: 2003/12/11 08:41:50 $
27 */
28 public class MetaClassIOASM
29 implements MetaClassIO
30 {
31 /*** Constant with instance of MetaClassIO. */
32 public static final MetaClassIOASM IO = new MetaClassIOASM();
33
34 /*** Name of Attribute containing MetaClass descriptor. */
35 static final String ATTRIBUTE_NAME = "MetaClassDescriptor";
36
37 /*** Extension used to find resource where metadata stored. */
38 private static final String EXTENSION = ".class";
39
40 /***
41 * @see MetaClassIO#getResourceName(String)
42 */
43 public String getResourceName( final String classname )
44 {
45 return classname.replace( '.', File.separatorChar ) + EXTENSION;
46 }
47
48 /***
49 * @see MetaClassIO#deserializeClass(InputStream)
50 */
51 public ClassDescriptor deserializeClass( final InputStream input )
52 throws Exception
53 {
54 final ExtractMetaDataVisitor cv = visitClassFile( input );
55 final IOException ioe = cv.getIoe();
56 final ClassDescriptor descriptor = cv.getClassDescriptor();
57 if( null != ioe )
58 {
59 throw new MetaClassException( ioe.getMessage(), ioe );
60 }
61 else if( null == descriptor )
62 {
63 final String message = "The .class file does " +
64 "not define MetaClass Descriptor Attribute.";
65 throw new MetaClassException( message );
66 }
67 else
68 {
69 return descriptor;
70 }
71 }
72
73 /***
74 * Visit class file specified by input.
75 *
76 * @param input the input
77 * @return the visitor post-visit
78 * @throws IOException if error reading class
79 */
80 ExtractMetaDataVisitor visitClassFile( final InputStream input )
81 throws IOException
82 {
83 final ClassReader reader = new ClassReader( input );
84 final ExtractMetaDataVisitor cv = new ExtractMetaDataVisitor();
85 reader.accept( cv, false );
86 return cv;
87 }
88
89 /***
90 * @see MetaClassIO#writeDescriptor(File, ClassDescriptor)
91 */
92 public void writeDescriptor( final File baseDir,
93 final ClassDescriptor descriptor )
94 throws Exception
95 {
96 final String filename = getResourceName( descriptor.getName() );
97 final File file = new File( baseDir, filename ).getCanonicalFile();
98 final File backup =
99 new File( baseDir, filename + ".bak" ).getCanonicalFile();
100
101 if( !file.exists() || !file.isFile() )
102 {
103 final String message = file + " is not a file";
104 throw new Exception( message );
105 }
106
107 backup.delete();
108 file.renameTo( backup );
109 try
110 {
111 serializeDescriptor( file, backup, descriptor );
112 backup.delete();
113 }
114 catch( final Exception e )
115 {
116 file.delete();
117 backup.renameTo( file );
118 }
119 }
120
121 /***
122 * Serialize class copying from input .class file to output.
123 *
124 * @param input the input .class file
125 * @param output the output .class file
126 * @param descriptor the descriptor
127 * @throws Exception if unable to output descriptor
128 */
129 void serializeDescriptor( final File input,
130 final File output,
131 final ClassDescriptor descriptor )
132 throws Exception
133 {
134 InputStream inputStream = null;
135 OutputStream outputStream = null;
136 try
137 {
138 inputStream = new FileInputStream( output );
139 outputStream = new FileOutputStream( input );
140 serializeClass( inputStream, outputStream, descriptor );
141 }
142 finally
143 {
144 if( null != outputStream )
145 {
146 outputStream.close();
147 }
148 if( null != inputStream )
149 {
150 inputStream.close();
151 }
152 }
153 }
154
155 /***
156 * Write a ClassDescriptor to an output stream.
157 *
158 * @param output the stream to write class descriptor out to
159 * @param descriptor the ClassDescriptor to write out
160 * @throws Exception if unable ot write class descriptor
161 */
162 public void serializeClass( final InputStream input,
163 final OutputStream output,
164 final ClassDescriptor descriptor )
165 throws Exception
166 {
167 final ClassReader reader = new ClassReader( input );
168 final ClassWriter cw = new ClassWriter( true );
169 final AddMetaDataAdapter cv = new AddMetaDataAdapter( cw, descriptor );
170 reader.accept( cv, false );
171 final byte[] bytes = cw.toByteArray();
172 output.write( bytes );
173 output.flush();
174 }
175 }