Fixed bug regarding the skipping of unmodified builds
[hibernate4-maven-plugin] / src / main / java / de / juplo / plugins / hibernate / ModificationTracker.java
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 : properties.keySet())
130       if (!propertyNames.contains(property))
131       {
132         modified = true;
133         properties.remove(property);
134       }
135     for (String clazz : 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 }