View Javadoc

1   /*
2    * Copyright (C) The MetaClass Group. All rights reserved.
3    *
4    * This software is published under the terms of the Spice
5    * Software License version 1.1, a copy of which has been included
6    * with this distribution in the LICENSE.txt file.
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 }