001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.java.source;
043:
044: import com.sun.source.tree.ClassTree;
045: import com.sun.source.tree.MethodTree;
046: import com.sun.source.tree.Tree;
047: import com.sun.source.tree.TypeParameterTree;
048: import com.sun.source.tree.VariableTree;
049: import com.sun.tools.javac.api.JavacTaskImpl;
050: import com.sun.tools.javac.code.Kinds;
051: import com.sun.tools.javac.code.Symbol;
052: import com.sun.tools.javac.code.Symbol.ClassSymbol;
053: import com.sun.tools.javac.code.Types;
054: import com.sun.tools.javac.comp.TransTypes;
055: import com.sun.tools.javac.model.LazyTreeLoader;
056: import com.sun.tools.javac.util.Context;
057: import com.sun.tools.javac.util.Log;
058: import java.io.File;
059: import java.io.IOException;
060: import java.io.PrintWriter;
061: import java.net.URL;
062: import java.util.HashMap;
063: import java.util.Map;
064: import java.util.logging.Level;
065: import java.util.logging.Logger;
066: import javax.tools.JavaFileManager;
067: import javax.tools.JavaFileObject;
068: import javax.tools.StandardLocation;
069: import org.netbeans.api.java.source.ClasspathInfo;
070: import org.netbeans.api.java.source.SourceUtils;
071: import org.netbeans.modules.java.source.parsing.FileObjects;
072: import org.netbeans.modules.java.source.usages.ClasspathInfoAccessor;
073: import org.netbeans.modules.java.source.usages.Index;
074: import org.netbeans.modules.java.source.usages.SymbolDumper;
075: import org.openide.filesystems.FileObject;
076: import org.openide.util.Exceptions;
077:
078: /**
079: *
080: * @author Dusan Balek
081: */
082: public class TreeLoader extends LazyTreeLoader {
083:
084: public static void preRegister(final Context context,
085: final ClasspathInfo cpInfo) {
086: context.put(lazyTreeLoaderKey, new TreeLoader(context, cpInfo));
087: }
088:
089: private static final Logger LOGGER = Logger
090: .getLogger(TreeLoader.class.getName());
091:
092: private Context context;
093: private ClasspathInfo cpInfo;
094: private Map<ClassSymbol, StringBuilder> couplingErrors;
095:
096: private TreeLoader(Context context, ClasspathInfo cpInfo) {
097: this .context = context;
098: this .cpInfo = cpInfo;
099: }
100:
101: @Override
102: public boolean loadTreeFor(final ClassSymbol clazz) {
103: assert JavaSourceAccessor.getINSTANCE().isJavaCompilerLocked();
104:
105: if (clazz != null) {
106: try {
107: FileObject fo = SourceUtils.getFile(clazz, cpInfo);
108: JavacTaskImpl jti = context.get(JavacTaskImpl.class);
109: if (fo != null && jti != null) {
110: Log.instance(context).nerrors = 0;
111: JavaFileObject jfo = FileObjects.nbFileObject(fo,
112: null);
113: Map<ClassSymbol, StringBuilder> oldCouplingErrors = couplingErrors;
114: try {
115: couplingErrors = new HashMap<ClassSymbol, StringBuilder>();
116: jti.analyze(jti.enter(jti.parse(jfo)));
117: dumpSymFile(clazz);
118: return true;
119: } finally {
120: for (Map.Entry<ClassSymbol, StringBuilder> e : couplingErrors
121: .entrySet()) {
122: logCouplingError(e.getKey(), e.getValue()
123: .toString());
124: }
125: couplingErrors = oldCouplingErrors;
126: }
127: }
128: } catch (IOException ex) {
129: Exceptions.printStackTrace(ex);
130: }
131: }
132: return false;
133: }
134:
135: @Override
136: public void couplingError(ClassSymbol clazz, Tree t) {
137: StringBuilder info = new StringBuilder("\n"); //NOI18N
138: switch (t.getKind()) {
139: case CLASS:
140: info.append("CLASS: ").append(
141: ((ClassTree) t).getSimpleName().toString()); //NOI18N
142: break;
143: case VARIABLE:
144: info.append("VARIABLE: ").append(
145: ((VariableTree) t).getName().toString()); //NOI18N
146: break;
147: case METHOD:
148: info.append("METHOD: ").append(
149: ((MethodTree) t).getName().toString()); //NOI18N
150: break;
151: case TYPE_PARAMETER:
152: info.append("TYPE_PARAMETER: ").append(
153: ((TypeParameterTree) t).getName().toString()); //NOI18N
154: break;
155: default:
156: info.append("TREE: <unknown>"); //NOI18N
157: break;
158: }
159: if (clazz != null && couplingErrors != null) {
160: StringBuilder sb = couplingErrors.get(clazz);
161: if (sb != null)
162: sb.append(info);
163: else
164: couplingErrors.put(clazz, info);
165: } else {
166: logCouplingError(clazz, info.toString());
167: }
168: }
169:
170: private void logCouplingError(ClassSymbol clazz, String info) {
171: JavaFileObject classFile = clazz != null ? clazz.classfile
172: : null;
173: String cfURI = classFile != null ? classFile.toUri()
174: .toASCIIString() : "<unknown>"; //NOI18N
175: JavaFileObject sourceFile = clazz != null ? clazz.sourcefile
176: : null;
177: String sfURI = classFile != null ? sourceFile.toUri()
178: .toASCIIString() : "<unknown>"; //NOI18N
179: LOGGER
180: .log(
181: Level.WARNING,
182: "Coupling error:\nclass file: {0}\nsource file: {1}{2}\n",
183: new Object[] { cfURI, sfURI, info });
184: }
185:
186: private void dumpSymFile(ClassSymbol clazz) throws IOException {
187: PrintWriter writer = null;
188: File outputFile = null;
189: boolean deleteResult = false;
190: try {
191: JavaFileManager fm = ClasspathInfoAccessor.getINSTANCE()
192: .getFileManager(cpInfo);
193: String binaryName = null;
194: if (clazz.classfile != null) {
195: binaryName = fm.inferBinaryName(
196: StandardLocation.PLATFORM_CLASS_PATH,
197: clazz.classfile);
198: if (binaryName == null)
199: binaryName = fm.inferBinaryName(
200: StandardLocation.CLASS_PATH,
201: clazz.classfile);
202: } else if (clazz.sourcefile != null) {
203: binaryName = fm.inferBinaryName(
204: StandardLocation.SOURCE_PATH, clazz.sourcefile);
205: }
206: if (binaryName == null) {
207: return;
208: }
209: String surl = clazz.classfile.toUri().toURL()
210: .toExternalForm();
211: int index = surl.lastIndexOf(FileObjects
212: .convertPackage2Folder(binaryName));
213: assert index > 0;
214: File classes = Index.getClassFolder(new URL(surl.substring(
215: 0, index)));
216: String pkg, name;
217: index = binaryName.lastIndexOf('.');
218: if (index < 0) {
219: pkg = null;
220: name = binaryName;
221: } else {
222: pkg = binaryName.substring(0, index);
223: assert binaryName.length() > index;
224: name = binaryName.substring(index + 1);
225: }
226: if (pkg != null) {
227: classes = new File(classes, pkg.replace('.',
228: File.separatorChar));
229: if (!classes.exists())
230: classes.mkdirs();
231: }
232: outputFile = new File(classes, name + '.' + FileObjects.SIG);
233: if (outputFile.exists())
234: return;//no point in dumping again already existing sig file
235: deleteResult = true;
236: writer = new PrintWriter(outputFile, "UTF-8");
237: Symbol owner;
238: if (clazz.owner.kind == Kinds.PCK) {
239: owner = null;
240: } else if (clazz.owner.kind == Kinds.VAR) {
241: owner = clazz.owner.owner;
242: } else {
243: owner = clazz.owner;
244: }
245: deleteResult = SymbolDumper.dump(writer, Types
246: .instance(context), TransTypes.instance(context),
247: clazz, owner);
248: } finally {
249: if (writer != null)
250: writer.close();
251: if (deleteResult) {
252: assert outputFile != null;
253:
254: outputFile.delete();
255: }
256: }
257: }
258: }
|