package act.app; /*- * #%L * ACT Framework * %% * Copyright (C) 2014 - 2017 ActFramework * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import act.util.ClassNames; import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; import org.osgl.$; import org.osgl.util.*; import java.io.File; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; /** * Encapsulate java srccode unit data including srccode code, byte code etc. * A java srccode unit specifies a java class */ public class Source { public enum State { /** * The Source instance has been created */ CREATED, /** * Source code loaded */ LOADED, /** * Byte code compiled out of the srccode code */ COMPILED, /** * Tried to compile but there is compile error */ ERROR_COMPILE, /** * File deleted */ DELETED, /** * Byte code enhanced by framework */ ENHANCED } // the srccode file private File file; // the class className. Can't be 1-1 map to file as // embedded classes do not have separate srccode file private String simpleName; private String packageName; private String className; // The srccode code private String code; // The byte code private byte[] bytes; private Map<String, byte[]> innerBytes = C.newMap(); private State state = State.CREATED; private ICompilationUnit compilationUnit; private boolean isController; private long ts; private Source(File file, String className) { E.NPE(file, className); this.file = file; this.simpleName = S.afterLast(className, "."); this.packageName = S.beforeLast(className, "."); this.className = className; compilationUnit = _compilationUnit(); } public String simpleName() { return simpleName; } public String packageName() { return packageName; } public String className() { return className; } public String code() { if (null == code) { load(); } return code; } public List<String> lines() { return C.listOf(code.split("\n")); } public byte[] bytes() { return bytes; } public byte[] bytes(String innerClass) { return innerBytes.get(innerClass); } public Set<String> innerClassNames() { return innerBytes.keySet(); } public File file() { return file; } public void load() { code = IO.readContentAsString(file); updateState(State.LOADED); } public void markAsController() { isController = true; } public boolean isController() { return isController; } void compiled(byte[] bytecode) { this.bytes = $.notNull(bytecode); updateState(State.COMPILED); } void compiled(String innerClassName, byte[] bytecode) { innerBytes.put(innerClassName, bytecode); } void enhanced(byte[] bytecode) { this.bytes = $.notNull(bytecode); updateState(State.ENHANCED); } public void refresh() { bytes = null; ts = 0L; tryLoadSourceFile(); } private void updateState(State state) { this.state = state; this.ts = $.ms(); } private void tryLoadSourceFile() { if (file.exists()) { code = IO.readContentAsString(file); updateState(State.LOADED); } else { updateState(State.DELETED); } } public static Source ofFile(File sourceRoot, File file) { String className = Util.className(sourceRoot, file); return null == className ? null : new Source(file, className); } public static Source ofClass(List<File> sourceRoots, String className) { File file = Util.sourceFile(sourceRoots, className); if (null != file) { return new Source(file, className); } return null; } public static Source ofInnerClass(File sourceFile, String innerClassName) { return new Source(sourceFile, innerClassName); } private ICompilationUnit _compilationUnit() { return new ICompilationUnit() { char[] mainTypeName = _mainTypeName(); char[][] packageName = _packageName(); char[] fileName = _fileName(); @Override public char[] getContents() { return code().toCharArray(); } @Override public char[] getMainTypeName() { return mainTypeName; } private char[] _mainTypeName() { String s = simpleName(); int pos = s.indexOf('$'); if (pos > -1) { s = s.substring(0, pos); } return s.toCharArray(); } @Override public char[][] getPackageName() { return packageName; } char[][] _packageName() { StringTokenizer tokens = new StringTokenizer(packageName(), "."); char[][] ca = new char[tokens.countTokens()][]; for (int i = 0; i < ca.length; i++) { ca[i] = tokens.nextToken().toCharArray(); } return ca; } @Override public boolean ignoreOptionalProblems() { return false; } @Override public char[] getFileName() { return fileName; } char[] _fileName() { String s = simpleName(); int pos = s.indexOf('$'); if (pos > -1) { s = s.substring(0, pos); } s = s.replace('.', '/'); s = s + ".java"; return s.toCharArray(); } }; } ICompilationUnit compilationUnit() { return compilationUnit; } public enum Util { ; public static String className(File sourceRoot, File file) { return ClassNames.sourceFileNameToClassName(sourceRoot, file.getAbsolutePath()); } public static File sourceFile(List<File> sourceRoots, String className) { FastStr s = FastStr.of(className).beforeFirst('$'); s = s.replace('.', File.separatorChar).append(".java"); for (File sourceRoot : sourceRoots) { File file = new File(sourceRoot, s.toString()); if (file.canRead()) { return file; } } return null; } public static void main(String[] args) throws Exception { } } }