1 32 package net.sf.retrotranslator.transformer; 33 34 import edu.emory.mathcs.backport.java.util.Queue; 35 import java.io.*; 36 import java.net.URL ; 37 import java.util.*; 38 import net.sf.retrotranslator.runtime.impl.*; 39 40 43 class FileTranslator { 44 45 private static final String CLASS_DESCRIPTOR_PATH = getFileName(ClassDescriptor.class); 46 private static final String SIGNATURES_PATH = getFileName(ClassDescriptor.class, ClassDescriptor.SIGNATURES_NAME); 47 48 private final ClassTransformer classTransformer; 49 private final TextFileTransformer fileTransformer; 50 private final EmbeddingConverter converter; 51 private final SystemLogger logger; 52 private final SourceMask mask; 53 54 public FileTranslator(ClassTransformer classTransformer, TextFileTransformer fileTransformer, 55 EmbeddingConverter converter, SystemLogger logger, SourceMask mask) { 56 this.classTransformer = classTransformer; 57 this.fileTransformer = fileTransformer; 58 this.converter = converter; 59 this.logger = logger; 60 this.mask = mask; 61 } 62 63 public void transform(FileContainer source, FileContainer destination) { 64 logger.log(new Message(Level.INFO, "Transforming " + source.getFileCount() + " file(s)" + 65 (source == destination ? " in " + source : " from " + source + " to " + destination) + ".")); 66 for (FileEntry entry : source.getEntries()) { 67 transform(entry, source, destination); 68 } 69 source.flush(logger); 70 logger.log(new Message(Level.INFO, 71 "Transformation of " + source.getFileCount() + " file(s) completed successfully.")); 72 } 73 74 private void transform(FileEntry entry, FileContainer source, FileContainer destination) { 75 String name = entry.getName(); 76 if (converter != null && name.equals(SIGNATURES_PATH)) { 77 destination.putEntry(converter.convertFileName(name), transformSignatures(entry.getContent())); 78 } else if (mask.matches(name)) { 79 logger.setFile(source.getLocation(), name); 80 logger.logForFile(Level.VERBOSE, "Transformation"); 81 byte[] sourceData = entry.getContent(); 82 byte[] resultData = TransformerTools.isClassFile(sourceData) 83 ? classTransformer.transform(sourceData, 0, sourceData.length) 84 : fileTransformer.transform(sourceData, converter); 85 String fixedName = converter == null ? name : converter.convertFileName(name); 86 if (source != destination || sourceData != resultData || !fixedName.equals(name)) { 87 if (!fixedName.equals(name)) destination.removeEntry(name); 88 destination.putEntry(fixedName, resultData); 89 } 90 } else if (source != destination) { 91 destination.putEntry(entry.getName(), entry.getContent()); 92 } 93 } 94 95 public void embed(FileContainer destination) { 96 Map<String , Boolean > runtimeNames = converter.getRuntimeFileNames(); 97 Map<String , Boolean > concurrentNames = converter.getConcurrentFileNames(); 98 if (runtimeNames.isEmpty() && concurrentNames.isEmpty()) { 99 return; 100 } 101 logger.log(new Message(Level.INFO, "Embedding backported classes")); 102 FileContainer runtimeContainer = findContainer(ClassDescriptor.class); 103 FileContainer concurrentContainer = findContainer(Queue.class); 104 while (true) { 105 if (embed(runtimeContainer, destination, runtimeNames) && 106 embed(concurrentContainer, destination, concurrentNames)) { 107 break; 108 } 109 } 110 logger.log(new Message(Level.INFO, "Embedding of backported classes completed successfully.")); 111 } 112 113 private boolean embed(FileContainer source, FileContainer destination, Map<String , Boolean > fileNames) { 114 boolean finished = true; 115 for (FileEntry entry : source.getEntries()) { 116 Boolean processed = fileNames.get(entry.getName()); 117 if (Boolean.FALSE.equals(processed)) { 118 transform(entry, source, destination); 119 String name = entry.getName(); 120 fileNames.put(name, Boolean.TRUE); 121 if (name.equals(CLASS_DESCRIPTOR_PATH)) { 122 fileNames.put(SIGNATURES_PATH, Boolean.FALSE); 123 } 124 finished = false; 125 } 126 } 127 return finished; 128 } 129 130 private byte[] transformSignatures(byte[] content) { 131 try { 132 NameTranslator transformer = new NameTranslator() { 133 protected String typeName(String s) { 134 return converter.convertClassName(s); 135 } 136 }; 137 Properties source = new Properties(); 138 source.load(new ByteArrayInputStream(content)); 139 Properties target = new Properties(); 140 for (Map.Entry entry : source.entrySet()) { 141 String key = converter.convertClassName((String ) entry.getKey()); 142 String value = transformer.declarationSignature((String ) entry.getValue()); 143 target.put(key, value); 144 } 145 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 146 target.store(stream, null); 147 return stream.toByteArray(); 148 } catch (IOException e) { 149 throw new RuntimeException (e); 150 } 151 } 152 153 private static FileContainer findContainer(Class aClass) { 154 String path = "/" + getFileName(aClass); 155 URL resource = aClass.getResource(path); 156 if (resource == null) { 157 throw new IllegalArgumentException ("Location not found: " + aClass); 158 } 159 String url = resource.toExternalForm(); 160 String prefix = "jar:file:"; 161 String suffix = "!" + path; 162 if (!url.startsWith(prefix) || !url.endsWith(suffix)) { 163 throw new IllegalArgumentException ("Not in a jar file: " + aClass); 164 } 165 File file = new File(url.substring(prefix.length(), url.length() - suffix.length())); 166 if (!file.isFile()) { 167 throw new IllegalArgumentException ("File not found: " + file); 168 } 169 return new JarFileContainer(file); 170 } 171 172 private static String getFileName(Class aClass) { 173 return aClass.getName().replace('.', '/') + RuntimeTools.CLASS_EXTENSION; 174 } 175 176 private static String getFileName(Class aClass, String fileName) { 177 return aClass.getPackage().getName().replace('.', '/') + "/" + fileName; 178 } 179 180 } 181 | Popular Tags |