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.j2seproject.applet;
043:
044: import com.sun.source.tree.CompilationUnitTree;
045: import com.sun.source.tree.Tree;
046: import com.sun.source.util.TreePath;
047: import com.sun.source.util.Trees;
048: import java.io.*;
049: import java.net.*;
050: import java.util.*;
051: import javax.lang.model.element.Modifier;
052: import javax.lang.model.element.TypeElement;
053: import javax.lang.model.element.TypeElement;
054: import javax.lang.model.util.Elements;
055: import javax.lang.model.util.Types;
056: import org.netbeans.api.java.source.CancellableTask;
057: import org.netbeans.api.java.source.CompilationController;
058: import org.netbeans.api.java.source.JavaSource;
059: import org.netbeans.modules.java.j2seproject.J2SEProjectUtil;
060:
061: import org.openide.*;
062: import org.openide.modules.SpecificationVersion;
063: import org.openide.filesystems.*;
064: import org.openide.util.*;
065:
066: import org.netbeans.api.java.classpath.*;
067: import org.netbeans.spi.java.classpath.support.*;
068: import org.netbeans.api.java.queries.*;
069: import org.netbeans.api.project.*;
070:
071: import org.netbeans.api.java.platform.*;
072:
073: import org.openide.loaders.*;
074: import org.openide.cookies.*;
075:
076: /** Support for execution of applets.
077: *
078: * @author Ales Novak, Martin Grebac
079: */
080: public class AppletSupport {
081:
082: // JDK issue #6193279: Appletviewer does not accept encoded URLs
083: private static final SpecificationVersion JDK_15 = new SpecificationVersion(
084: "1.5"); // NOI18N
085:
086: /** constant for html extension */
087: private static final String HTML_EXT = "html"; // NOI18N
088: /** constant for class extension */
089: private static final String CLASS_EXT = "class"; // NOI18N
090:
091: private final static String POLICY_FILE_NAME = "applet";
092: private final static String POLICY_FILE_EXT = "policy";
093:
094: private AppletSupport() {
095: }
096:
097: // Used only from unit tests to suppress detection of applet. If value
098: // is different from null it will be returned instead.
099: public static Boolean unitTestingSupport_isApplet = null;
100:
101: public static boolean isApplet(final FileObject file) {
102: if (file == null) {
103: return false;
104: }
105: // support for unit testing
106: if (unitTestingSupport_isApplet != null) {
107: return unitTestingSupport_isApplet.booleanValue();
108: }
109: JavaSource js = JavaSource.forFileObject(file);
110: if (js == null) {
111: return false;
112: }
113: final boolean[] result = new boolean[] { false };
114: try {
115: js.runUserActionTask(
116: new CancellableTask<CompilationController>() {
117:
118: public void run(CompilationController control)
119: throws Exception {
120: if (JavaSource.Phase.ELEMENTS_RESOLVED
121: .compareTo(control
122: .toPhase(JavaSource.Phase.ELEMENTS_RESOLVED)) <= 0) {
123: Elements elements = control
124: .getElements();
125: Trees trees = control.getTrees();
126: Types types = control.getTypes();
127: TypeElement applet = elements
128: .getTypeElement("java.applet.Applet"); //NOI18N
129: TypeElement japplet = elements
130: .getTypeElement("javax.swing.JApplet"); //NOI18N
131: CompilationUnitTree cu = control
132: .getCompilationUnit();
133: List<? extends Tree> topLevels = cu
134: .getTypeDecls();
135: for (Tree topLevel : topLevels) {
136: if (topLevel.getKind() == Tree.Kind.CLASS) {
137: TypeElement type = (TypeElement) trees
138: .getElement(TreePath
139: .getPath(cu,
140: topLevel));
141: if (type != null) {
142: Set<Modifier> modifiers = type
143: .getModifiers();
144: if (modifiers
145: .contains(Modifier.PUBLIC)
146: && ((applet != null && types
147: .isSubtype(
148: type
149: .asType(),
150: applet
151: .asType())) || (japplet != null && types
152: .isSubtype(
153: type
154: .asType(),
155: japplet
156: .asType())))) {
157: result[0] = true;
158: break;
159: }
160: }
161: }
162: }
163: }
164: }
165:
166: public void cancel() {
167: }
168: }, true);
169: } catch (IOException ioe) {
170: Exceptions.printStackTrace(ioe);
171: }
172: return result[0];
173: }
174:
175: /**
176: * @return html file with the same name as applet
177: */
178: private static FileObject generateHtml(FileObject appletFile,
179: FileObject buildDir, FileObject classesDir)
180: throws IOException {
181: FileObject htmlFile = buildDir.getFileObject(appletFile
182: .getName(), HTML_EXT);
183:
184: if (htmlFile == null) {
185: htmlFile = buildDir.createData(appletFile.getName(),
186: HTML_EXT);
187: }
188:
189: FileLock lock = htmlFile.lock();
190: PrintWriter writer = null;
191: try {
192: writer = new PrintWriter(htmlFile.getOutputStream(lock));
193: ClassPath cp = ClassPath.getClassPath(appletFile,
194: ClassPath.EXECUTE);
195: ClassPath sp = ClassPath.getClassPath(appletFile,
196: ClassPath.SOURCE);
197: String path = FileUtil.getRelativePath(sp
198: .findOwnerRoot(appletFile), appletFile);
199: path = path.substring(0, path.length() - 5);
200: String codebase = FileUtil.getRelativePath(buildDir,
201: classesDir);
202: if (codebase == null) {
203: codebase = classesDir.getURL().toString();
204: }
205: fillInFile(writer, path + "." + CLASS_EXT, "codebase=\""
206: + codebase + "\""); // NOI18N
207: } finally {
208: lock.releaseLock();
209: if (writer != null)
210: writer.close();
211: }
212: return htmlFile;
213: }
214:
215: /**
216: * @return html file with the same name as applet
217: */
218: public static FileObject generateSecurityPolicy(
219: FileObject projectDir) {
220:
221: FileObject policyFile = projectDir.getFileObject(
222: POLICY_FILE_NAME, POLICY_FILE_EXT);
223:
224: try {
225: if (policyFile == null) {
226: policyFile = projectDir.createData(POLICY_FILE_NAME,
227: POLICY_FILE_EXT);
228: }
229: FileLock lock = policyFile.lock();
230: PrintWriter writer = null;
231: try {
232: writer = new PrintWriter(policyFile
233: .getOutputStream(lock));
234: fillInPolicyFile(writer);
235: } finally {
236: lock.releaseLock();
237: if (writer != null)
238: writer.close();
239: }
240: } catch (IOException ioe) {
241: ErrorManager.getDefault().log(
242: ErrorManager.INFORMATIONAL,
243: "Problem when generating applet policy file: "
244: + ioe); //NOI18N
245: }
246: return policyFile;
247: }
248:
249: /**
250: * @return URL of the html file with the same name as sibling
251: */
252: public static URL generateHtmlFileURL(FileObject appletFile,
253: FileObject buildDir, FileObject classesDir,
254: String activePlatform) throws FileStateInvalidException {
255: FileObject html = null;
256: IOException ex = null;
257: if ((appletFile == null) || (buildDir == null)
258: || (classesDir == null)) {
259: return null;
260: }
261: try {
262: html = generateHtml(appletFile, buildDir, classesDir);
263: if (html != null) {
264: return getHTMLPageURL(html, activePlatform);
265: } else {
266: return null;
267: }
268: } catch (IOException iex) {
269: return null;
270: }
271: }
272:
273: /**
274: * Creates an URL of html page passed to the appletviewer. It workarounds a JDK 1.5 appletviewer
275: * bug. The appletviewer is not able to handle escaped URLs.
276: * @param htmlFile html page
277: * @param activePlatform identifier of the platform used in the project
278: * @return URL of the html page or null
279: */
280: public static URL getHTMLPageURL(FileObject htmlFile,
281: String activePlatform) {
282: assert htmlFile != null : "htmlFile cannot be null"; //NOI18N
283: // JDK issue #6193279: Appletviewer does not accept encoded URLs
284: JavaPlatform platform = J2SEProjectUtil
285: .getActivePlatform(activePlatform);
286: boolean workAround6193279 = platform != null //In case of nonexisting platform don't use the workaround
287: && platform.getSpecification().getVersion().compareTo(
288: JDK_15) >= 0; //JDK1.5 and higher
289: URL url = null;
290: if (workAround6193279) {
291: File f = FileUtil.toFile(htmlFile);
292: try {
293: String path = f.getAbsolutePath();
294: if (File.separatorChar != '/') { //NOI18N
295: path = path.replace(File.separatorChar, '/'); //NOI18N
296: }
297: url = new URL("file", null, path);
298: } catch (MalformedURLException e) {
299: ErrorManager.getDefault().notify(e);
300: }
301: } else {
302: try {
303: url = htmlFile.getURL();
304: } catch (FileStateInvalidException f) {
305: ErrorManager.getDefault().notify(f);
306: }
307: }
308: return url;
309: }
310:
311: /** fills in file with html source so it is html file with applet
312: * @param file is a file to be filled
313: * @param name is name of the applet
314: */
315: private static void fillInFile(PrintWriter writer, String name,
316: String codebase) {
317: ResourceBundle bundle = NbBundle.getBundle(AppletSupport.class);
318:
319: writer.println("<HTML>"); // NOI18N
320: writer.println("<HEAD>"); // NOI18N
321:
322: writer.print(" <TITLE>"); // NOI18N
323: writer.print(bundle.getString("GEN_title"));
324: writer.println("</TITLE>"); // NOI18N
325:
326: writer.println("</HEAD>"); // NOI18N
327: writer.println("<BODY>\n"); // NOI18N
328:
329: writer.print(bundle.getString("GEN_warning"));
330:
331: writer.print("<H3><HR WIDTH=\"100%\">"); // NOI18N
332: writer.print(bundle.getString("GEN_header"));
333: writer.println("<HR WIDTH=\"100%\"></H3>\n"); // NOI18N
334:
335: writer.println("<P>"); // NOI18N
336: // String codebase = getCodebase (name);
337: if (codebase == null)
338: writer.print("<APPLET code="); // NOI18N
339: else
340: writer.print("<APPLET " + codebase + " code="); // NOI18N
341: writer.print("\""); // NOI18N
342:
343: writer.print(name);
344: writer.print("\""); // NOI18N
345:
346: writer.println(" width=350 height=200></APPLET>"); // NOI18N
347: writer.println("</P>\n"); // NOI18N
348:
349: writer.print("<HR WIDTH=\"100%\"><FONT SIZE=-1><I>"); // NOI18N
350: writer.print(bundle.getString("GEN_copy"));
351: writer.println("</I></FONT>"); // NOI18N
352:
353: writer.println("</BODY>"); // NOI18N
354: writer.println("</HTML>"); // NOI18N
355: writer.flush();
356: }
357:
358: /** fills in policy file with all permissions granted
359: * @param writer is a file to be filled
360: */
361: private static void fillInPolicyFile(PrintWriter writer) {
362: writer.println("grant {"); // NOI18N
363: writer.println("permission java.security.AllPermission;"); // NOI18N
364: writer.println("};"); // NOI18N
365: writer.flush();
366: }
367: }
|