View Javadoc
1   package de.juplo.plugins.hibernate;
2   
3   
4   import java.io.File;
5   import java.io.FileInputStream;
6   import java.io.FileOutputStream;
7   import java.io.IOException;
8   import java.io.InputStream;
9   import java.io.ObjectInputStream;
10  import java.io.ObjectOutputStream;
11  import java.math.BigInteger;
12  import java.security.MessageDigest;
13  import java.security.NoSuchAlgorithmException;
14  import java.util.HashMap;
15  import java.util.HashSet;
16  import java.util.Map;
17  import java.util.Properties;
18  import java.util.Set;
19  import org.apache.maven.plugin.logging.Log;
20  
21  
22  
23  /**
24   *
25   * @author Kai Moritz
26   */
27  public class ModificationTracker
28  {
29    private Map<String,String> properties;
30    private Map<String,String> classes;
31  
32    private final Set<String> propertyNames;
33    private final Set<String> classNames;
34  
35    private boolean modified = false;
36    private boolean failed = false;
37  
38    private final File saved;
39    private final MessageDigest digest;
40    private final Log log;
41  
42  
43    ModificationTracker(String buildDirectory, String filename, Log log)
44        throws
45          NoSuchAlgorithmException
46    {
47      propertyNames = new HashSet<String>();
48      classNames = new HashSet<String>();
49      File output = new File(filename + ".md5s");
50      if (output.isAbsolute())
51      {
52        saved = output;
53      }
54      else
55      {
56        // Interpret relative file path relative to build directory
57        saved = new File(buildDirectory, output.getPath());
58        log.debug("Adjusted relative path, resulting path is " + saved.getPath());
59      }
60      digest = java.security.MessageDigest.getInstance("MD5");
61      this.log = log;
62    }
63  
64  
65    private String calculate(InputStream is)
66        throws
67          IOException
68    {
69      byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
70      int i;
71      while((i = is.read(buffer)) > -1)
72        digest.update(buffer, 0, i);
73      is.close();
74      byte[] bytes = digest.digest();
75      BigInteger bi = new BigInteger(1, bytes);
76      return String.format("%0" + (bytes.length << 1) + "x", bi);
77    }
78  
79    private boolean check(Map<String,String> values, String name, String value)
80    {
81      if (!values.containsKey(name) || !values.get(name).equals(value))
82      {
83        values.put(name, value);
84        return true;
85      }
86      else
87        return false;
88    }
89  
90  
91    boolean track(String name, InputStream is) throws IOException
92    {
93      boolean result = check(classes, name, calculate(is));
94      classNames.add(name);
95      modified |= result;
96      return result;
97    }
98  
99  
100   boolean check(String name, String property)
101   {
102     propertyNames.add(name);
103     return check(properties, name, property);
104   }
105 
106   boolean track(String name, String property)
107   {
108     boolean result = check(name, property);
109     modified |= result;
110     return result;
111   }
112 
113   boolean track(Properties properties)
114   {
115     boolean result = false;
116     for (String name : properties.stringPropertyNames())
117       result |= track(name, properties.getProperty(name));
118     return result;
119   }
120 
121 
122   void touch()
123   {
124     modified = true;
125   }
126 
127   boolean modified()
128   {
129     for (String property : new HashSet<String>(properties.keySet()))
130       if (!propertyNames.contains(property))
131       {
132         modified = true;
133         properties.remove(property);
134       }
135      for (String clazz : new HashSet<String>(classes.keySet()))
136       if (!classNames.contains(clazz))
137       {
138         modified = true;
139         classes.remove(clazz);
140       }
141     return modified;
142   }
143 
144 
145   void failed()
146   {
147     failed = true;
148   }
149 
150 
151   void load()
152   {
153     if (saved.isFile() && saved.length() > 0)
154     {
155       try
156       {
157         FileInputStream fis = new FileInputStream(saved);
158         ObjectInputStream ois = new ObjectInputStream(fis);
159         properties = (HashMap<String,String>)ois.readObject();
160         classes = (HashMap<String,String>)ois.readObject();
161         ois.close();
162       }
163       catch (Exception e)
164       {
165         properties = new HashMap<String,String>();
166         classes = new HashMap<String,String>();
167         log.warn("Cannot read md5s from saved: " + e);
168       }
169     }
170     else
171     {
172       properties = new HashMap<String,String>();
173       classes = new HashMap<String,String>();
174       try
175       {
176         saved.createNewFile();
177       }
178       catch (IOException e)
179       {
180         log.debug("Cannot create file \"" + saved.getPath() + "\" for md5s: " + e);
181       }
182     }
183   }
184 
185   void save()
186   {
187     if (failed)
188     {
189       saved.delete();
190       return;
191     }
192 
193     if (!modified)
194       return;
195 
196     /** Write md5-sums for annotated classes to file */
197     try
198     {
199       FileOutputStream fos = new FileOutputStream(saved);
200       ObjectOutputStream oos = new ObjectOutputStream(fos);
201       oos.writeObject(properties);
202       oos.writeObject(classes);
203       oos.close();
204       fos.close();
205     }
206     catch (Exception e)
207     {
208       log.error("Cannot write md5-sums to file: " + e);
209     }
210   }  
211 }