001 package org.shiftone.jrat.inject.process;
002
003
004 import org.shiftone.jrat.core.JRatException;
005 import org.shiftone.jrat.inject.Injector;
006 import org.shiftone.jrat.inject.InjectorOptions;
007 import org.shiftone.jrat.inject.bytecode.Transformer;
008 import org.shiftone.jrat.util.Assert;
009 import org.shiftone.jrat.util.io.IOUtil;
010 import org.shiftone.jrat.util.log.Logger;
011
012 import java.io.File;
013 import java.io.InputStream;
014 import java.io.OutputStream;
015
016
017 /**
018 * @author jeff@shiftone.org (Jeff Drost)
019 * <p/>
020 * todo - this logic should all go in the Injector.
021 */
022 public abstract class AbstractFileProcessor implements FileProcessor {
023
024 private static final Logger LOG = Logger.getLogger(AbstractFileProcessor.class);
025 private static final long DEFAULT_BUFFER_SIZE = 1024 * 6;
026 private boolean forceOverwrite = true; // false;
027 private boolean overwriteNewer = false;
028 private boolean preserveLastModified = false;
029
030 public void process(Transformer transformer, InjectorOptions options, File source, File target) {
031
032 LOG.debug("process " + source.getAbsolutePath() + " " + target.getAbsolutePath());
033 Assert.assertNotNull("transformer", transformer);
034
035 long lastModified;
036
037 if (!source.exists()) {
038 throw new JRatException("source file does not exist : " + source);
039 }
040
041 LOG.debug("source exists");
042
043 if (source.isDirectory()) {
044 throw new JRatException("source file is a directory : " + source);
045 }
046
047 LOG.debug("source is real file (not dir)");
048
049 if (source.canRead() == false) {
050 throw new JRatException("source file can not be read (check permissions): " + source);
051 }
052
053 LOG.debug("source can be read");
054
055 lastModified = source.lastModified();
056
057 if (target.exists()) {
058 LOG.debug("target exists " + target.getAbsolutePath());
059
060 if (forceOverwrite == false) {
061 throw new JRatException("target exists and forceOverwrite is disabled : " + source);
062 }
063
064 if (target.isDirectory()) {
065 throw new JRatException("target is directory : " + target);
066 }
067
068 if (target.canWrite() == false) {
069 throw new JRatException("unable to write to target (check permissions) : " + target);
070 }
071
072 // newer is bigger
073 if (target.lastModified() > source.lastModified()) {
074
075 // target is newer than source
076 if (!overwriteNewer) {
077 throw new JRatException("target is newer than source and overwriteNewer is disabled : "
078 + source);
079 }
080 }
081
082 processUsingSwapFile(transformer, options, source, target);
083 } else {
084 LOG.debug("target does not exist " + target.getAbsolutePath());
085 processFile(transformer, options, source, target);
086 }
087
088 if (preserveLastModified) {
089 target.setLastModified(lastModified);
090 }
091 }
092
093
094 protected void processUsingSwapFile(Transformer transformer, InjectorOptions options, File source, File target) {
095
096 LOG.debug("processUsingSwapFile " + source.getAbsolutePath() + " " + target.getAbsolutePath());
097
098 File workFile = new File(target.getAbsolutePath() + Injector.WORK_FILE_END);
099
100 if (workFile.exists()) {
101 LOG.info("workfile found, deleting");
102 IOUtil.delete(workFile);
103 }
104
105 try {
106 processFile(transformer, options, source, workFile);
107
108 if (!workFile.exists()) {
109 throw new JRatException("processFile seems to have worked, but target file doesn't exist : "
110 + source);
111 }
112
113 IOUtil.rename(workFile, target, true);
114 }
115 catch (Throwable e) {
116 String msg = "Failed to instrument " + source + " : " + e;
117
118 if ((workFile.exists()) && (!workFile.delete())) {
119 msg += " and couldn't delete the corrupt file " + workFile.getAbsolutePath();
120 }
121
122 throw new JRatException(msg, e);
123 }
124 finally {
125 IOUtil.deleteIfExists(workFile);
126 }
127 }
128
129
130 protected void processFile(Transformer transformer, InjectorOptions options, File source, File target) {
131
132 int bufferSize = (int) Math.min(DEFAULT_BUFFER_SIZE, source.length());
133 InputStream inputStream = null;
134 OutputStream outputStream = null;
135
136 try {
137 inputStream = IOUtil.openInputStream(source, bufferSize);
138 outputStream = IOUtil.openOutputStream(target, bufferSize);
139
140 LOG.debug("calling processStream");
141 processStream(transformer, options, inputStream, outputStream, source.getName());
142 }
143 finally {
144 IOUtil.close(inputStream);
145 IOUtil.close(outputStream);
146 }
147 }
148
149
150 protected void processStream(
151 Transformer transformer, InjectorOptions options, InputStream inputStream, OutputStream outputStream, String fileName) {
152 throw new UnsupportedOperationException("processStream should be implemented by derived class");
153 }
154 }