123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- /* *******************************************************************
- * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * PARC initial implementation
- * ******************************************************************/
-
- package org.aspectj.weaver.bcel;
-
- import java.io.BufferedOutputStream;
- import java.io.File;
- import java.io.IOException;
- import java.util.Collections;
- import java.util.List;
-
- import org.aspectj.apache.bcel.classfile.JavaClass;
- import org.aspectj.util.FileUtil;
- import org.aspectj.weaver.IUnwovenClassFile;
-
- public class UnwovenClassFile implements IUnwovenClassFile {
- protected String filename;
- protected char[] charfilename;
- protected byte[] bytes;
- // protected JavaClass javaClass = null;
- // protected byte[] writtenBytes = null;
- protected List<ChildClass> writtenChildClasses = Collections.emptyList();
- protected String className = null;
- protected boolean isModule = false;
-
- public UnwovenClassFile(String filename, byte[] bytes) {
- this.filename = filename;
- this.isModule = filename.toLowerCase().endsWith("module-info.java");
- this.bytes = bytes;
- }
-
- /** Use if the classname is known, saves a bytecode parse */
- public UnwovenClassFile(String filename, String classname, byte[] bytes) {
- this.filename = filename;
- this.isModule = filename.toLowerCase().endsWith("module-info.class");
- this.className = classname;
- this.bytes = bytes;
- }
-
- public boolean shouldBeWoven() {
- // Skip module-info files for now, they aren't really types
- return !isModule;
- }
-
- public String getFilename() {
- return filename;
- }
-
- public String makeInnerFileName(String innerName) {
- String prefix = filename.substring(0, filename.length() - 6); // strip the .class
- return prefix + "$" + innerName + ".class";
- }
-
- public byte[] getBytes() {
- // if (bytes == null) bytes = javaClass.getBytes();
- return bytes;
- }
-
- public JavaClass getJavaClass() {
- // XXX need to know when to make a new class and when not to
- // XXX this is an important optimization
- if (getBytes() == null) {
- System.out.println("no bytes for: " + getFilename());
- // Thread.currentThread().dumpStack();
- Thread.dumpStack();
- }
- return Utility.makeJavaClass(filename, getBytes());
- // if (javaClass == null) javaClass = Utility.makeJavaClass(filename, getBytes());
- // return javaClass;
- }
-
- public void writeUnchangedBytes() throws IOException {
- writeWovenBytes(getBytes(), Collections.<ChildClass>emptyList());
- }
-
- public void writeWovenBytes(byte[] bytes, List<ChildClass> childClasses) throws IOException {
- writeChildClasses(childClasses);
-
- // System.err.println("should write: " + getClassName());
-
- // System.err.println("about to write: " + this + ", " + writtenBytes + ", ");
- // + writtenBytes != null + " && " + unchanged(bytes, writtenBytes) );
-
- // if (writtenBytes != null && unchanged(bytes, writtenBytes)) return;
-
- // System.err.println(" actually wrote it");
-
- BufferedOutputStream os = FileUtil.makeOutputStream(new File(filename));
- os.write(bytes);
- os.close();
-
- // writtenBytes = bytes;
- }
-
- private void writeChildClasses(List<ChildClass> childClasses) throws IOException {
- // ??? we only really need to delete writtenChildClasses whose
- // ??? names aren't in childClasses; however, it's unclear
- // ??? how much that will affect performance
- deleteAllChildClasses();
-
- childClasses.removeAll(writtenChildClasses); // XXX is this right
-
- for (ChildClass childClass : childClasses) {
- writeChildClassFile(childClass.name, childClass.bytes);
- }
-
- writtenChildClasses = childClasses;
-
- }
-
- private void writeChildClassFile(String innerName, byte[] bytes) throws IOException {
- BufferedOutputStream os = FileUtil.makeOutputStream(new File(makeInnerFileName(innerName)));
- os.write(bytes);
- os.close();
- }
-
- protected void deleteAllChildClasses() {
- for (ChildClass childClass : writtenChildClasses) {
- deleteChildClassFile(childClass.name);
- }
- }
-
- protected void deleteChildClassFile(String innerName) {
- File childClassFile = new File(makeInnerFileName(innerName));
- childClassFile.delete();
- }
-
- /* private */static boolean unchanged(byte[] b1, byte[] b2) {
- int len = b1.length;
- if (b2.length != len)
- return false;
- for (int i = 0; i < len; i++) {
- if (b1[i] != b2[i])
- return false;
- }
- return true;
- }
-
- public char[] getClassNameAsChars() {
- if (charfilename == null) {
- charfilename = getClassName().replace('.', '/').toCharArray();
- }
- return charfilename;
- }
-
- public String getClassName() {
- if (className == null)
- className = getJavaClass().getClassName(); // OPTIMIZE quicker way to determine name??? surely?
- return className;
- }
-
- @Override
- public String toString() {
- return "UnwovenClassFile(" + filename + ", " + getClassName() + ")";
- }
-
- // record
- // OPTIMIZE why is the 'short name' used here (the bit after the dollar) - seems we mess about a lot trimming it off only to put
- // it back on!
- public static class ChildClass {
- public final String name;
- public final byte[] bytes;
-
- ChildClass(String name, byte[] bytes) {
- this.name = name;
- this.bytes = bytes;
- }
-
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof ChildClass))
- return false;
- ChildClass o = (ChildClass) other;
- return o.name.equals(name) && unchanged(o.bytes, bytes);
- }
-
- @Override
- public int hashCode() {
- return name.hashCode();
- }
-
- @Override
- public String toString() {
- return "(ChildClass " + name + ")";
- }
- }
-
- public void setClassNameAsChars(char[] classNameAsChars) {
- this.charfilename = classNameAsChars;
- }
- }
|