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.parsing;
043:
044: import java.io.File;
045: import java.io.IOException;
046: import java.net.URI;
047: import java.net.URL;
048: import java.util.Iterator;
049: import java.util.List;
050: import java.util.logging.Level;
051: import java.util.logging.Logger;
052: import javax.tools.JavaFileObject;
053: import org.netbeans.api.java.classpath.ClassPath;
054: import org.openide.filesystems.FileObject;
055: import org.openide.filesystems.FileUtil;
056:
057: /**
058: *
059: * @author Tomas Zezula
060: */
061: public class OutputFileManager extends CachingFileManager {
062:
063: /**
064: * Exception used to signal that the sourcepath is broken (project is deleted)
065: */
066: public class InvalidSourcePath extends IllegalStateException {
067:
068: }
069:
070: private static boolean debug = Boolean
071: .getBoolean("org.netbeans.modules.java.source.parsing.OutputFileManager.debug"); //NOI18N
072:
073: private ClassPath scp;
074:
075: /** Creates a new instance of CachingFileManager */
076: public OutputFileManager(CachingArchiveProvider provider,
077: final ClassPath outputClassPath, final ClassPath sourcePath) {
078: super (provider, outputClassPath, false, true);
079: assert sourcePath != null && outputClassPath != null;
080: this .scp = sourcePath;
081: }
082:
083: public @Override
084: JavaFileObject getJavaFileForOutput(Location l, String className,
085: JavaFileObject.Kind kind, javax.tools.FileObject sibling)
086: throws IOException, UnsupportedOperationException,
087: IllegalArgumentException {
088:
089: if (kind != JavaFileObject.Kind.CLASS) {
090: throw new IllegalArgumentException();
091: } else {
092: int index;
093: if (sibling != null) {
094: index = getActiveRoot(sibling);
095: } else {
096: index = getActiveRoot(FileObjects
097: .convertPackage2Folder(className));
098: }
099: if (index == -1) {
100: //Deleted project
101: throw new InvalidSourcePath();
102: }
103: if (index < 0 && sibling != null
104: && !(new File(sibling.toUri()).exists())) {
105: //Deleted project
106: throw new InvalidSourcePath();
107: }
108: assert index >= 0 : "class: " + className + " sibling: "
109: + sibling + " srcRoots: " + this .scp
110: + " cacheRoots: " + this .cp;
111: assert index < this .cp.entries().size() : "index " + index
112: + " class: " + className + " sibling: " + sibling
113: + " srcRoots: " + this .scp + " cacheRoots: "
114: + this .cp;
115: File activeRoot = new File(URI.create(this .cp.entries()
116: .get(index).getURL().toExternalForm()));
117: String baseName = className
118: .replace('.', File.separatorChar); //NOI18N
119: String nameStr = baseName + '.' + FileObjects.SIG;
120: int nameComponentIndex = nameStr
121: .lastIndexOf(File.separatorChar);
122: if (nameComponentIndex != -1) {
123: String pathComponent = nameStr.substring(0,
124: nameComponentIndex);
125: new File(activeRoot, pathComponent).mkdirs();
126: } else {
127: activeRoot.mkdirs();
128: }
129: File f = FileUtil.normalizeFile(new File(activeRoot,
130: nameStr));
131: return OutputFileObject.create(activeRoot, f);
132: }
133: }
134:
135: public @Override
136: javax.tools.FileObject getFileForOutput(Location l, String pkgName,
137: String relativeName, javax.tools.FileObject sibling)
138: throws IOException, UnsupportedOperationException,
139: IllegalArgumentException {
140: assert pkgName != null;
141: assert relativeName != null;
142: if (sibling == null) {
143: throw new IllegalArgumentException("sibling == null");
144: }
145: final int index = getActiveRoot(sibling);
146: if (index == -1) {
147: //Deleted project
148: throw new InvalidSourcePath();
149: }
150: assert index >= 0 && index < this .cp.entries().size();
151: File activeRoot = new File(URI.create(this .cp.entries().get(
152: index).getURL().toExternalForm()));
153: File folder;
154: if (pkgName.length() == 0) {
155: folder = activeRoot;
156: } else {
157: folder = new File(activeRoot, FileObjects
158: .convertPackage2Folder(pkgName));
159: }
160: if (!folder.exists()) {
161: if (!folder.mkdirs()) {
162: throw new IOException();
163: }
164: }
165: File file = FileUtil.normalizeFile(new File(folder,
166: relativeName));
167: return OutputFileObject.create(activeRoot, file);
168: }
169:
170: private int getActiveRoot(final javax.tools.FileObject file)
171: throws IOException {
172: List<ClassPath.Entry> entries = this .scp.entries();
173: int eSize = entries.size();
174: if (eSize == 1) {
175: return 0;
176: }
177: if (eSize == 0) {
178: return -1;
179: }
180: Iterator<ClassPath.Entry> it = entries.iterator();
181: for (int i = 0; it.hasNext(); i++) {
182: URL rootUrl = it.next().getURL();
183: if (isParentOf(rootUrl, file.toUri().toURL())) {
184: return i;
185: }
186: }
187: return -2;
188: }
189:
190: private boolean isParentOf(URL folder, final URL file)
191: throws IOException {
192: assert folder != null && file != null;
193: return file.toExternalForm()
194: .startsWith(folder.toExternalForm());
195: }
196:
197: private int getActiveRoot(String baseName) {
198: List<ClassPath.Entry> entries = this .scp.entries();
199: int eSize = entries.size();
200: if (eSize == 1) {
201: return 0;
202: }
203: if (eSize == 0) {
204: return -1;
205: }
206: String name, parent = null;
207: int index = baseName.lastIndexOf('/'); //NOI18N
208: if (index < 0) {
209: name = baseName;
210: } else {
211: parent = baseName.substring(0, index);
212: name = baseName.substring(index + 1);
213: }
214: index = name.indexOf('$'); //NOI18N
215: if (index > 0) {
216: name = name.substring(0, index);
217: }
218: Iterator<ClassPath.Entry> it = entries.iterator();
219: for (int i = 0; it.hasNext(); i++) {
220: FileObject root = it.next().getRoot();
221: if (root != null) {
222: FileObject parentFile = root.getFileObject(parent);
223: if (parentFile != null) {
224: if (parentFile
225: .getFileObject(name, FileObjects.JAVA) != null) {
226: return i;
227: }
228: }
229: }
230: }
231: return -2;
232: }
233:
234: private static boolean debug(String message) {
235: if (debug) {
236: Logger.getLogger("global").log(Level.INFO, message);
237: }
238: return true;
239: }
240:
241: }
|