001: /**
002: * Copyright (C) 2001-2004 France Telecom R&D
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */package org.objectweb.speedo.generation.recompiler;
018:
019: import org.objectweb.speedo.generation.mivisitor.MetaInfoVisitorImpl;
020: import org.objectweb.speedo.generation.mivisitor.MetaInfoVisitor;
021: import org.objectweb.speedo.generation.api.SpeedoCompilerParameter;
022: import org.objectweb.speedo.lib.Personality;
023: import org.objectweb.speedo.metadata.SpeedoXMLDescriptor;
024: import org.objectweb.speedo.metadata.SpeedoClass;
025: import org.objectweb.speedo.api.SpeedoException;
026: import org.objectweb.speedo.mapper.lib.Object2StringSerializer;
027: import org.objectweb.speedo.tools.StringReplace;
028: import org.objectweb.speedo.mim.api.PersistentObjectItf;
029: import org.objectweb.util.monolog.api.BasicLevel;
030:
031: import java.io.File;
032: import java.util.List;
033: import java.util.ArrayList;
034: import java.util.Arrays;
035: import java.net.URLClassLoader;
036: import java.net.URL;
037: import java.net.MalformedURLException;
038:
039: /**
040: * Checks the date of the source and the built files:
041: * - .jdo / JMI file
042: * - .java / .class
043: *
044: * For each .jdo file, if the .jdo or a .java has been modified all classes
045: * are removed in order to re-enhance all classed.
046: *
047: * TODO: check aware classes
048: *
049: * @author S.Chassande-Barrioz
050: */
051: public class UpToDateVisitor extends MetaInfoVisitorImpl {
052: private File output;
053: private File input;
054: private ClassLoader classloader;
055: private List xmlsToRemove;
056: private List enhancedClasses;
057:
058: /**
059: * builds a MetaInfoVisitor which is the last of the chain
060: */
061: public UpToDateVisitor(Personality p) {
062: super (p);
063: }
064:
065: /**
066: * builds a MetaInfoVisitor which is the last of the chain
067: */
068: public UpToDateVisitor(MetaInfoVisitor mim, Personality p) {
069: super (mim, p);
070: }
071:
072: protected String getLoggerName() {
073: return super .getLoggerName() + ".uptodate";
074: }
075:
076: public String getTitle() {
077: return "Computing classes requiring enhancement ...";
078: }
079:
080: public boolean init() throws SpeedoException {
081: super .init();
082: output = new File(scp.output);
083: if (!output.exists() && output.mkdirs()) {
084: throw new SpeedoException(
085: "Impossible to create the output directory: "
086: + output.getAbsolutePath());
087: }
088: input = new File(scp.input);
089: if (!input.exists()) {
090: throw new SpeedoException("No input directory: "
091: + input.getAbsolutePath());
092: }
093: try {
094: classloader = new URLClassLoader(new URL[] { new File(
095: scp.output).toURL() }, getClass().getClassLoader());
096: } catch (MalformedURLException e) {
097:
098: }
099: enhancedClasses = new ArrayList();
100: return !scp.getXmldescriptor().isEmpty();
101: }
102:
103: public void visitCompilerParameter(SpeedoCompilerParameter scp)
104: throws SpeedoException {
105: super .visitCompilerParameter(scp);
106: if (xmlsToRemove != null) {
107: for (int i = (xmlsToRemove.size() - 1); i >= 0; i--) {
108: SpeedoXMLDescriptor xml = (SpeedoXMLDescriptor) xmlsToRemove
109: .get(i);
110: scp.getXmldescriptor().remove(xml.xmlFile);
111: }
112: }
113: }
114:
115: public void visitXml(SpeedoXMLDescriptor xml)
116: throws SpeedoException {
117: //compare the date of the .jdo and JMI files
118: File xmlFile = new File(scp.xmlDir, xml.xmlFile);
119: File jmiFile = new File(output, Object2StringSerializer
120: .descFileName2ClassName(xml.xmlFile)
121: + ".class");
122: if (debug) {
123: logger.log(BasicLevel.DEBUG, "XML file: "
124: + xmlFile.getAbsolutePath() + "\n\ttime="
125: + xmlFile.lastModified());
126: if (jmiFile.exists()) {
127: logger.log(BasicLevel.DEBUG, "JMI file: "
128: + jmiFile.getAbsolutePath() + "\n\ttime="
129: + jmiFile.lastModified());
130: } else {
131: logger.log(BasicLevel.DEBUG, "NO JMI file found : "
132: + jmiFile.getAbsolutePath());
133: }
134: }
135: xml.requireEnhancement = !jmiFile.exists()
136: || (xmlFile.lastModified() > jmiFile.lastModified());
137: if (debug) {
138: logger.log(BasicLevel.DEBUG, "Enhancement "
139: + (xml.requireEnhancement ? "" : "not ")
140: + "required for the jdo file:" + xml.xmlFile);
141: }
142: enhancedClasses.clear();
143: super .visitXml(xml);
144: List classes = xml.getSpeedoClasses();
145:
146: if (!xml.requireEnhancement) {
147: for (int i = (classes.size() - 1); i >= 0
148: && !xml.requireEnhancement; i--) {
149: SpeedoClass sc = (SpeedoClass) classes.get(i);
150: sc.setRequireEnhancement(xml.requireEnhancement);
151: }
152: }
153: if (xml.requireEnhancement) {
154: logger.log(BasicLevel.INFO, "Enhancement required for :"
155: + xml.xmlFile);
156:
157: //Remove the JMI file
158: if (debug) {
159: logger.log(BasicLevel.DEBUG, "Removing the jmi file:"
160: + jmiFile.getAbsolutePath());
161: }
162: if (jmiFile.exists() && !jmiFile.delete()) {
163: throw new SpeedoException(
164: "Impossible to remove the JMI file associated to the jdo file:"
165: + xml.xmlFile);
166: }
167:
168: for (int i = (enhancedClasses.size() - 1); i >= 0; i--) {
169: SpeedoClass sc = (SpeedoClass) enhancedClasses.get(i);
170: String baseName = StringReplace.replaceChar('.',
171: File.separatorChar, sc.getFQName());
172: File classFile = new File(output, baseName + ".class");
173: if (debug) {
174: logger.log(BasicLevel.DEBUG,
175: "Removing class files:" + classFile);
176: }
177: if (classFile.exists() && !classFile.delete()) {
178: throw new SpeedoException(
179: "Impossible to remove the file:"
180: + classFile.getAbsolutePath());
181: }
182: }
183: } else {
184: if (xmlsToRemove == null) {
185: xmlsToRemove = new ArrayList();
186: }
187: xmlsToRemove.add(xml);
188: }
189: enhancedClasses.clear();//garbage
190: }
191:
192: public void visitClass(SpeedoClass sc) throws SpeedoException {
193: super .visitClass(sc);
194: SpeedoXMLDescriptor xml = sc.moPackage.xmlDescriptor;
195: sc.setRequireEnhancement(xml.requireEnhancement);
196: String baseName = StringReplace.replaceChar('.',
197: File.separatorChar, sc.getFQName());
198: File classFile = new File(output, baseName + ".class");
199: boolean classExist = classFile.exists();
200: if (debug) {
201: logger.log(BasicLevel.DEBUG, "Examining the class: "
202: + sc.getFQName());
203: if (classExist) {
204: logger.log(BasicLevel.DEBUG, "class file: "
205: + classFile.getAbsolutePath());
206: }
207: }
208:
209: boolean javaModified = !classExist;
210: if (classExist) {
211: //compare the date of the .java and .class files
212: File javaFile = new File(scp.input, baseName + ".java");
213: logger.log(BasicLevel.DEBUG, "java file: "
214: + javaFile.getAbsolutePath());
215: javaModified = (javaFile.lastModified() > classFile
216: .lastModified());
217:
218: if (!javaModified) {
219: // Is the class already enhanced ?
220: try {
221: Class clazz = classloader.loadClass(sc.getFQName());
222: sc.setAlreadyEnhanced(implement(clazz,
223: PersistentObjectItf.class));
224: } catch (NoClassDefFoundError e) {
225: logger.log(BasicLevel.DEBUG, "Class "
226: + sc.getFQName(), e);
227: javaModified = true; //in order to delete and recompile the class
228: } catch (ClassNotFoundException e) {
229: logger.log(BasicLevel.DEBUG, "Class "
230: + sc.getFQName(), e);
231: } catch (ClassFormatError e) {
232: logger.log(BasicLevel.DEBUG, "Class "
233: + sc.getFQName(), e);
234: } catch (Throwable e) {
235: String msg = "Impossible to analyze the class '"
236: + sc.getFQName() + "': ";
237: logger.log(BasicLevel.ERROR, msg, e);
238: throw new SpeedoException(msg);
239: }
240: if (debug) {
241: logger.log(BasicLevel.DEBUG, "The class "
242: + sc.getFQName() + " is "
243: + (sc.isAlreadyEnhanced() ? "" : "not ")
244: + "already enhanced.");
245: }
246: }
247: }
248: if (classExist && javaModified) {
249: logger.log(BasicLevel.INFO, "The class " + sc.getFQName()
250: + " has been modified (Remove the .class).");
251: if (!classFile.delete()) {
252: throw new SpeedoException(
253: "Impossible to remove the file:"
254: + classFile.getAbsolutePath());
255: }
256: }
257: sc.setRequireEnhancement(!classExist || javaModified
258: || !sc.isAlreadyEnhanced());
259: if (!sc.requireEnhancement()) {
260: enhancedClasses.add(sc);
261: }
262:
263: //if this class requires the enhancement, the xml too
264: xml.requireEnhancement |= sc.requireEnhancement();
265: }
266:
267: private boolean implement(Class clazz, Class itf) {
268: boolean res = Arrays.asList(clazz.getInterfaces())
269: .contains(itf);
270: if (debug) {
271: logger.log(BasicLevel.DEBUG, "The class " + clazz.getName()
272: + " is " + (res ? "" : "not ") + "a "
273: + itf.getName());
274: }
275: return res
276: || (clazz.getSuperclass() != null && implement(clazz
277: .getSuperclass(), itf));
278: }
279: }
|