001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.bytecode;
031:
032: import com.caucho.util.Base64;
033: import com.caucho.util.CharBuffer;
034: import com.caucho.util.Log;
035: import com.caucho.vfs.PersistentDependency;
036:
037: import java.security.MessageDigest;
038: import java.util.Comparator;
039: import java.util.logging.Level;
040: import java.util.logging.Logger;
041:
042: /**
043: * Representing a class that might change.
044: */
045: public class JClassDependency implements PersistentDependency {
046: private final static Logger log = Log.open(JClassDependency.class);
047:
048: private String _className;
049:
050: private boolean _checkFields = true;
051: private boolean _checkStatic = true;
052: private boolean _checkProtected = true;
053: private boolean _checkPrivate = true;
054:
055: private boolean _isDigestModified;
056:
057: /**
058: * Creates the class dependency.
059: */
060: public JClassDependency(JClass cl) {
061: _className = cl.getName();
062: }
063:
064: /**
065: * Create a new dependency with a given digest.
066: *
067: * @param cl the source class
068: * @param digest the MD5 digest
069: */
070: public JClassDependency(JClass cl, String digest) {
071: _className = cl.getName();
072:
073: String newDigest = getDigest();
074:
075: if (!newDigest.equals(digest)) {
076: if (log.isLoggable(Level.FINE))
077: log.fine(_className + " digest is modified.");
078:
079: _isDigestModified = true;
080: }
081: }
082:
083: /**
084: * Create a new dependency with a given digest.
085: *
086: * @param cl the source class
087: * @param digest the MD5 digest
088: */
089: public JClassDependency(String className, String digest) {
090: }
091:
092: /**
093: * Returns true if the underlying resource has changed.
094: */
095: public boolean isModified() {
096: return _isDigestModified;
097: }
098:
099: /**
100: * Log the reason for modification
101: */
102: public boolean logModified(Logger log) {
103: if (isModified()) {
104: log.info(_className + " is modified");
105: return true;
106: } else
107: return false;
108: }
109:
110: /**
111: * Calculates a MD5 digest of the class.
112: */
113: public String getDigest() {
114: return "";
115: /*
116: try {
117: if (_cl == null)
118: return "";
119:
120: MessageDigest digest = MessageDigest.getInstance("MD5");
121:
122: addDigest(digest, _cl.getName());
123:
124: addDigest(digest, _cl.getModifiers());
125:
126: Class cl = _cl.getSuperclass();
127: if (cl != null)
128: addDigest(digest, cl.getName());
129:
130: Class []interfaces = _cl.getInterfaces();
131: for (int i = 0; i < interfaces.length; i++)
132: addDigest(digest, interfaces[i].getName());
133:
134: Field []fields = _cl.getFields();
135:
136: Arrays.sort(fields, new FieldComparator());
137:
138: if (_checkFields) {
139: for (int i = 0; i < fields.length; i++) {
140: if (Modifier.isPrivate(fields[i].getModifiers()) &&
141: ! _checkPrivate)
142: continue;
143: if (Modifier.isProtected(fields[i].getModifiers()) &&
144: ! _checkProtected)
145: continue;
146:
147: addDigest(digest, fields[i].getName());
148: addDigest(digest, fields[i].getModifiers());
149: addDigest(digest, fields[i].getType().getName());
150: }
151: }
152:
153: Method []methods = _cl.getMethods();
154: Arrays.sort(methods, new MethodComparator());
155:
156: for (int i = 0; i < methods.length; i++) {
157: Method method = methods[i];
158:
159: if (Modifier.isPrivate(method.getModifiers()) && ! _checkPrivate)
160: continue;
161: if (Modifier.isProtected(method.getModifiers()) && ! _checkProtected)
162: continue;
163: if (Modifier.isStatic(method.getModifiers()) && ! _checkStatic)
164: continue;
165:
166: addDigest(digest, method.getName());
167: addDigest(digest, method.getModifiers());
168: addDigest(digest, method.getName());
169:
170: Class []param = method.getParameterTypes();
171: for (int j = 0; j < param.length; j++)
172: addDigest(digest, param[j].getName());
173:
174: addDigest(digest, method.getReturnType().getName());
175:
176: Class []exn = method.getExceptionTypes();
177: for (int j = 0; j < exn.length; j++)
178: addDigest(digest, exn[j].getName());
179: }
180:
181: byte []digestBytes = new byte[256];
182:
183: int len = digest.digest(digestBytes, 0, digestBytes.length);
184:
185: return digestToBase64(digestBytes, len);
186: } catch (Exception e) {
187: log.log(Level.FINER, e.toString(), e);
188:
189: return "";
190: }
191: */
192: }
193:
194: /**
195: * Returns a string which will recreate the dependency.
196: */
197: public String getJavaCreateString() {
198: return ("new com.caucho.bytecode.JClassDependency(\""
199: + _className + "\", \"" + getDigest() + "\")");
200: }
201:
202: /**
203: * Adds the int to the digest.
204: */
205: private static void addDigest(MessageDigest digest, int v) {
206: digest.update((byte) (v >> 24));
207: digest.update((byte) (v >> 16));
208: digest.update((byte) (v >> 8));
209: digest.update((byte) v);
210: }
211:
212: /**
213: * Adds the string to the digest using a UTF8 encoding.
214: */
215: private static void addDigest(MessageDigest digest, String string) {
216: if (string == null)
217: return;
218:
219: int len = string.length();
220: for (int i = 0; i < len; i++) {
221: int ch = string.charAt(i);
222: if (ch < 0x80)
223: digest.update((byte) ch);
224: else if (ch < 0x800) {
225: digest.update((byte) (0xc0 + (ch >> 6)));
226: digest.update((byte) (0x80 + (ch & 0x3f)));
227: } else {
228: digest.update((byte) (0xe0 + (ch >> 12)));
229: digest.update((byte) (0x80 + ((ch >> 6) & 0x3f)));
230: digest.update((byte) (0x80 + (ch & 0x3f)));
231: }
232: }
233: }
234:
235: private String digestToBase64(byte[] digest, int len) {
236: CharBuffer cb = CharBuffer.allocate();
237:
238: Base64.encode(cb, digest, 0, len);
239:
240: return cb.close();
241: }
242:
243: public boolean isEqual(Object o) {
244: if (o == this )
245: return true;
246:
247: if (!(o instanceof JClassDependency))
248: return false;
249:
250: JClassDependency depend = (JClassDependency) o;
251:
252: return _className.equals(depend._className);
253: }
254:
255: static class FieldComparator implements Comparator<JField> {
256: public int compare(JField a, JField b) {
257: if (a == b)
258: return 0;
259: else if (a == null)
260: return -1;
261: else if (b == null)
262: return 1;
263: else if (a.equals(b))
264: return 0;
265:
266: int cmp = a.getName().compareTo(b.getName());
267: if (cmp != 0)
268: return cmp;
269:
270: cmp = a.getDeclaringClass().getName().compareTo(
271: b.getDeclaringClass().getName());
272: if (cmp != 0)
273: return cmp;
274:
275: return a.getType().getName().compareTo(
276: b.getType().getName());
277: }
278: }
279:
280: static class MethodComparator implements Comparator<JMethod> {
281: public int compare(JMethod a, JMethod b) {
282: if (a == b)
283: return 0;
284: else if (a == null)
285: return -1;
286: else if (b == null)
287: return 1;
288: else if (a.equals(b))
289: return 0;
290:
291: int cmp = a.getName().compareTo(b.getName());
292: if (cmp != 0)
293: return cmp;
294:
295: JClass[] paramA = a.getParameterTypes();
296: JClass[] paramB = b.getParameterTypes();
297:
298: if (paramA.length < paramB.length)
299: return -1;
300: else if (paramB.length < paramA.length)
301: return 1;
302:
303: for (int i = 0; i < paramA.length; i++) {
304: cmp = paramA[i].getName()
305: .compareTo(paramB[i].getName());
306: if (cmp != 0)
307: return cmp;
308: }
309:
310: cmp = a.getDeclaringClass().getName().compareTo(
311: b.getDeclaringClass().getName());
312: if (cmp != 0)
313: return cmp;
314:
315: return a.getReturnType().getName().compareTo(
316: b.getReturnType().getName());
317: }
318: }
319: }
|