1 /* Copyright 2004 The Apache Software Foundation 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package org.apache.xmlbeans.impl.util; 17 18 import org.apache.xmlbeans.Filer; 19 20 import java.io.IOException; 21 import java.io.File; 22 import java.io.Writer; 23 import java.io.FileReader; 24 import java.io.FileOutputStream; 25 import java.io.FileWriter; 26 import java.io.OutputStream; 27 import java.io.OutputStreamWriter; 28 import java.io.StringReader; 29 import java.io.StringWriter; 30 import java.nio.charset.Charset; 31 import java.nio.charset.CharsetEncoder; 32 import java.nio.charset.CodingErrorAction; 33 import java.util.Set; 34 import java.util.HashSet; 35 import java.util.List; 36 import java.util.ArrayList; 37 38 import repackage.Repackager; 39 40 /** 41 * This implementation of Filer writes to disk. 42 */ 43 public class FilerImpl implements Filer 44 { 45 private File classdir; 46 private File srcdir; 47 private Repackager repackager; 48 private boolean verbose; 49 private List sourceFiles; 50 private boolean incrSrcGen; 51 private Set seenTypes; 52 private static final Charset CHARSET; 53 54 static 55 { 56 Charset temp = null; 57 try 58 { 59 temp = Charset.forName(System.getProperty("file.encoding")); 60 } 61 catch (Exception e) {} 62 CHARSET = temp; 63 } 64 65 public FilerImpl(File classdir, File srcdir, Repackager repackager, boolean verbose, boolean incrSrcGen) 66 { 67 this.classdir = classdir; 68 this.srcdir = srcdir; 69 this.repackager = repackager; 70 this.verbose = verbose; 71 this.sourceFiles = (sourceFiles != null ? sourceFiles : new ArrayList()); 72 this.incrSrcGen = incrSrcGen; 73 if (this.incrSrcGen) 74 seenTypes = new HashSet(); 75 } 76 77 /** 78 * Creates a new schema binary file (.xsb) and returns a stream for writing to it. 79 * 80 * @param typename fully qualified type name 81 * @return a stream to write the type to 82 * @throws java.io.IOException 83 */ 84 public OutputStream createBinaryFile(String typename) throws IOException 85 { 86 if (verbose) 87 System.err.println("created binary: " + typename); 88 // KHK: for now the typename will already be a relative filename for the binary 89 //String filename = typename.replace('.', File.separatorChar) + ".xsb"; 90 File source = new File(classdir, typename); 91 source.getParentFile().mkdirs(); 92 93 return new FileOutputStream( source ); 94 } 95 96 /** 97 * Creates a new binding source file (.java) and returns a writer for it. 98 * 99 * @param typename fully qualified type name 100 * @return a stream to write the type to 101 * @throws java.io.IOException 102 */ 103 public Writer createSourceFile(String typename) throws IOException 104 { 105 if (incrSrcGen) 106 seenTypes.add(typename); 107 108 if (typename.indexOf('$') > 0) 109 { 110 typename = 111 typename.substring( 0, typename.lastIndexOf( '.' ) ) + "." + 112 typename.substring( typename.indexOf( '$' ) + 1 ); 113 } 114 115 String filename = typename.replace('.', File.separatorChar) + ".java"; 116 117 File sourcefile = new File(srcdir, filename); 118 sourcefile.getParentFile().mkdirs(); 119 if (verbose) 120 System.err.println("created source: " + sourcefile.getAbsolutePath()); 121 122 sourceFiles.add(sourcefile); 123 124 if (incrSrcGen && sourcefile.exists()) 125 { 126 // Generate the file in a buffer and then compare it to the 127 // file already on disk 128 return new IncrFileWriter(sourcefile, repackager); 129 } 130 else 131 { 132 return repackager == null ? 133 (Writer) writerForFile( sourcefile ) : 134 (Writer) new RepackagingWriter( sourcefile, repackager ); 135 } 136 } 137 138 public List getSourceFiles() 139 { 140 return new ArrayList(sourceFiles); 141 } 142 143 public Repackager getRepackager() 144 { 145 return repackager; 146 } 147 148 private static final Writer writerForFile(File f) throws IOException 149 { 150 if (CHARSET == null) 151 return new FileWriter(f); 152 153 FileOutputStream fileStream = new FileOutputStream(f); 154 CharsetEncoder ce = CHARSET.newEncoder(); 155 ce.onUnmappableCharacter(CodingErrorAction.REPORT); 156 return new OutputStreamWriter(fileStream, ce); 157 } 158 159 static class IncrFileWriter extends StringWriter 160 { 161 private File _file; 162 private Repackager _repackager; 163 164 public IncrFileWriter(File file, Repackager repackager) 165 { 166 _file = file; 167 _repackager = repackager; 168 } 169 170 public void close() throws IOException 171 { 172 super.close(); 173 174 // This is where all the real work happens 175 StringBuffer sb = _repackager != null ? 176 _repackager.repackage(getBuffer()) : 177 getBuffer(); 178 String str = sb.toString(); 179 List diffs = new ArrayList(); 180 StringReader sReader = new StringReader(str); 181 FileReader fReader = new FileReader(_file); 182 183 try 184 { 185 Diff.readersAsText(sReader, "<generated>", 186 fReader, _file.getName(), diffs); 187 } 188 finally 189 { 190 sReader.close(); 191 fReader.close(); 192 } 193 194 if (diffs.size() > 0) 195 { 196 // Diffs encountered, replace the file on disk with text from 197 // the buffer 198 Writer fw = writerForFile(_file); 199 try 200 { fw.write(str); } 201 finally 202 { fw.close(); } 203 } 204 else 205 ; // If no diffs, don't do anything 206 } 207 } 208 209 static class RepackagingWriter extends StringWriter 210 { 211 public RepackagingWriter ( File file, Repackager repackager ) 212 { 213 _file = file; 214 _repackager = repackager; 215 } 216 217 public void close ( ) throws IOException 218 { 219 super.close(); 220 221 Writer fw = writerForFile( _file ); 222 try 223 { fw.write( _repackager.repackage( getBuffer() ).toString() ); } 224 finally 225 { fw.close(); } 226 } 227 228 private File _file; 229 private Repackager _repackager; 230 } 231 }