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: // See #13931.
043: package org.netbeans.nbbuild;
044:
045: import java.io.ByteArrayInputStream;
046: import java.io.File;
047: import java.io.IOException;
048: import java.io.InputStream;
049: import java.io.OutputStream;
050: import java.net.MalformedURLException;
051: import java.net.URI;
052: import java.net.URISyntaxException;
053: import java.net.URL;
054: import java.net.URLClassLoader;
055: import java.net.URLConnection;
056: import java.net.URLStreamHandler;
057: import java.net.URLStreamHandlerFactory;
058: import java.util.ArrayList;
059: import java.util.Collections;
060: import java.util.Enumeration;
061: import java.util.HashMap;
062: import java.util.HashSet;
063: import java.util.Hashtable;
064: import java.util.Iterator;
065: import java.util.List;
066: import java.util.Locale;
067: import java.util.Map;
068: import java.util.Set;
069: import java.util.StringTokenizer;
070: import java.util.jar.JarEntry;
071: import java.util.jar.JarFile;
072: import java.util.jar.Manifest;
073: import javax.help.HelpSet;
074: import javax.help.HelpSetException;
075: import javax.help.IndexItem;
076: import javax.help.TOCItem;
077: import javax.help.TreeItem;
078: import javax.help.TreeItemFactory;
079: import javax.swing.tree.DefaultMutableTreeNode;
080: import javax.xml.parsers.SAXParser;
081: import javax.xml.parsers.SAXParserFactory;
082: import org.apache.tools.ant.BuildException;
083: import org.apache.tools.ant.FileScanner;
084: import org.apache.tools.ant.Location;
085: import org.apache.tools.ant.Project;
086: import org.apache.tools.ant.Task;
087: import org.apache.tools.ant.types.FileSet;
088: import org.apache.tools.ant.types.Mapper;
089: import org.xml.sax.Attributes;
090: import org.xml.sax.InputSource;
091: import org.xml.sax.SAXException;
092: import org.xml.sax.helpers.DefaultHandler;
093:
094: /** Task to check various aspects of JavaHelp helpsets.
095: * <ol>
096: * <li>General parsability as far as JavaHelp is concerned.
097: * <li>Map IDs are not duplicated.
098: * <li>Map IDs point to real HTML files (and anchors where specified).
099: * <li>TOC/Index navigators refer to real map IDs.
100: * <li>HTML links in reachable HTML files point to valid places (including anchors).
101: * </ol>
102: * @author Jesse Glick, Marek Slama
103: */
104: public class CheckHelpSetsBin extends Task {
105:
106: private List<FileSet> filesets = new ArrayList<FileSet>();
107:
108: private ClassLoader globalClassLoader;
109:
110: private Map<String, ClassLoader> classLoaderMap;
111:
112: private Set<String> excludedModulesSet;
113:
114: /** Add a fileset with one or more helpsets in it.
115: * <strong>Only</strong> the <samp>*.hs</samp> should match!
116: * All other files will be found from it.
117: */
118: public void addFileset(FileSet fs) {
119: filesets.add(fs);
120: }
121:
122: private URLClassLoader createGlobalClassLoader(File dir,
123: String[] files) {
124: List<File> globalFileList = new ArrayList<File>();
125: URL[] globalClassPath = null;
126: for (int i = 0; i < files.length; i++) {
127: List<File> fileList = new ArrayList<File>();
128: File moduleJar = new File(dir, files[i]);
129: fileList.add(moduleJar);
130: boolean hsFound = false;
131:
132: JarFile jar = null;
133: Manifest manifest = null;
134: try {
135: jar = new JarFile(moduleJar);
136: manifest = jar.getManifest();
137: } catch (IOException ex) {
138: ex.printStackTrace();
139: }
140: if (manifest == null) {
141: log("Manifest is not present in jar. Skipping.",
142: Project.MSG_WARN);
143: continue;
144: }
145: File parent = moduleJar.getParentFile();
146: java.util.jar.Attributes attrs = manifest
147: .getMainAttributes();
148:
149: String value = attrs.getValue("OpenIDE-Module");
150: if (value == null) {
151: log(
152: "Attribute OpenIDE-Module is not present in manifest. Skipping.",
153: Project.MSG_WARN);
154: continue;
155: }
156: //Look for *.hs
157: for (Enumeration en = jar.entries(); en.hasMoreElements();) {
158: JarEntry je = (JarEntry) en.nextElement();
159: if (je.getName().endsWith(".hs")) {
160: hsFound = true;
161: }
162: }
163: value = attrs.getValue("Class-Path");
164: if (value != null) {
165: StringTokenizer tok = new StringTokenizer(value);
166: while (tok.hasMoreElements()) {
167: String s = tok.nextToken();
168: File extJar = new File(parent, s);
169: fileList.add(extJar);
170: try {
171: jar = new JarFile(extJar);
172: } catch (IOException ex) {
173: log("Error: Cannot open file: " + extJar,
174: Project.MSG_WARN);
175: ex.printStackTrace();
176: }
177: //Look for *.hs
178: for (Enumeration en = jar.entries(); en
179: .hasMoreElements();) {
180: JarEntry je = (JarEntry) en.nextElement();
181: if (je.getName().endsWith(".hs")) {
182: hsFound = true;
183: }
184: }
185: }
186: }
187: if (hsFound) {
188: globalFileList.addAll(fileList);
189: }
190: }
191: globalClassPath = new URL[globalFileList.size()];
192: for (int i = 0; i < globalFileList.size(); i++) {
193: try {
194: globalClassPath[i] = globalFileList.get(i).toURI()
195: .toURL();
196: } catch (MalformedURLException ex) {
197: ex.printStackTrace();
198: }
199: }
200: return new URLClassLoader(globalClassPath, this .getClass()
201: .getClassLoader().getParent(),
202: new CheckHelpSetsBin.NbDocsStreamHandler.Factory());
203: }
204:
205: private Map<String, ClassLoader> createClassLoaderMap(File dir,
206: String[] files) {
207: Map<String, ClassLoader> m = new HashMap<String, ClassLoader>();
208: for (int i = 0; i < files.length; i++) {
209: List<File> fileList = new ArrayList<File>();
210: File moduleJar = new File(dir, files[i]);
211: fileList.add(moduleJar);
212: boolean hsFound = false;
213: URL[] classPath = null;
214:
215: JarFile jar = null;
216: Manifest manifest = null;
217: try {
218: jar = new JarFile(moduleJar);
219: manifest = jar.getManifest();
220: } catch (IOException ex) {
221: ex.printStackTrace();
222: }
223: if (manifest == null) {
224: log("Manifest is not present in jar. Skipping.",
225: Project.MSG_WARN);
226: continue;
227: }
228: File parent = moduleJar.getParentFile();
229: java.util.jar.Attributes attrs = manifest
230: .getMainAttributes();
231: String value = attrs.getValue("Class-Path");
232: if (value != null) {
233: StringTokenizer tok = new StringTokenizer(value);
234: while (tok.hasMoreElements()) {
235: String s = tok.nextToken();
236: File extJar = new File(parent, s);
237: fileList.add(extJar);
238: }
239: classPath = new URL[fileList.size()];
240: for (int j = 0; j < fileList.size(); j++) {
241: try {
242: classPath[j] = fileList.get(j).toURI().toURL();
243: } catch (MalformedURLException ex) {
244: ex.printStackTrace();
245: }
246: }
247: }
248:
249: String key = attrs.getValue("OpenIDE-Module");
250: if (key == null) {
251: log(
252: "Attribute OpenIDE-Module is not present in manifest. Skipping.",
253: Project.MSG_WARN);
254: continue;
255: }
256: int pos = key.indexOf("/");
257: if (pos != -1) {
258: key = key.substring(0, pos);
259: }
260: //Look for *.hs
261: for (Enumeration en = jar.entries(); en.hasMoreElements();) {
262: JarEntry je = (JarEntry) en.nextElement();
263: if (je.getName().endsWith(".hs")) {
264: hsFound = true;
265: }
266: }
267: value = attrs.getValue("Class-Path");
268: if (value != null) {
269: StringTokenizer tok = new StringTokenizer(value);
270: while (tok.hasMoreElements()) {
271: String s = tok.nextToken();
272: File extJar = new File(parent, s);
273: try {
274: jar = new JarFile(extJar);
275: } catch (IOException ex) {
276: log("Error: Cannot open file: " + extJar,
277: Project.MSG_WARN);
278: ex.printStackTrace();
279: }
280: //Look for *.hs
281: for (Enumeration en = jar.entries(); en
282: .hasMoreElements();) {
283: JarEntry je = (JarEntry) en.nextElement();
284: if (je.getName().endsWith(".hs")) {
285: hsFound = true;
286: }
287: }
288: }
289: }
290: if (hsFound) {
291: ClassLoader clParent = this .getClass().getClassLoader()
292: .getParent();
293: URLClassLoader moduleClassLoader = new URLClassLoader(
294: classPath,
295: clParent,
296: new CheckHelpSetsBin.NbDocsStreamHandler.Factory());
297: m.put(key, moduleClassLoader);
298: }
299: }
300: return m;
301: }
302:
303: private Set<String> parseExcludeModulesProperty(String prop) {
304: excludedModulesSet = new HashSet<String>();
305: if (prop == null) {
306: return excludedModulesSet;
307: }
308: String[] arr = prop.split(",");
309: for (int i = 0; i < arr.length; i++) {
310: excludedModulesSet.add(arr[i]);
311: }
312: return excludedModulesSet;
313: }
314:
315: public void execute() throws BuildException {
316: try {
317: URL
318: .setURLStreamHandlerFactory(new CheckHelpSetsBin.NbDocsStreamHandler.Factory());
319: } catch (Error ex) {
320: log("StreamHandlerFactory already set", Project.MSG_WARN);
321: }
322: String p = getProject().getProperty(
323: "javahelpbin.exclude.modules");
324: excludedModulesSet = parseExcludeModulesProperty(p);
325: Iterator it = filesets.iterator();
326: while (it.hasNext()) {
327: FileSet fs = (FileSet) it.next();
328: FileScanner scanner = fs.getDirectoryScanner(getProject());
329: File dir = scanner.getBasedir();
330: String[] files = scanner.getIncludedFiles();
331:
332: globalClassLoader = createGlobalClassLoader(dir, files);
333: classLoaderMap = createClassLoaderMap(dir, files);
334:
335: for (int i = 0; i < files.length; i++) {
336: List<File> fileList = new ArrayList<File>();
337: File moduleJar = new File(dir, files[i]);
338: fileList.add(moduleJar);
339: URL[] classPath = null;
340:
341: JarFile jar = null;
342: Manifest manifest = null;
343: try {
344: jar = new JarFile(moduleJar);
345: manifest = jar.getManifest();
346: } catch (IOException ex) {
347: ex.printStackTrace();
348: }
349: if (manifest == null) {
350: log("Manifest is not present in jar. Skipping.",
351: Project.MSG_WARN);
352: continue;
353: }
354: File parent = moduleJar.getParentFile();
355: java.util.jar.Attributes attrs = manifest
356: .getMainAttributes();
357:
358: String key = attrs.getValue("OpenIDE-Module");
359: if (key == null) {
360: log(
361: "Attribute OpenIDE-Module is not present in manifest. Skipping.",
362: Project.MSG_WARN);
363: continue;
364: }
365: int pos = key.indexOf("/");
366: if (pos != -1) {
367: key = key.substring(0, pos);
368: }
369: if (excludedModulesSet.contains(key)) {
370: log("", Project.MSG_WARN);
371: log("* * * *", Project.MSG_WARN);
372: log("Skip module: " + key, Project.MSG_WARN);
373: log("* * * *", Project.MSG_WARN);
374: continue;
375: }
376: URLClassLoader classLoader = (URLClassLoader) classLoaderMap
377: .get(key);
378: if (classLoader == null) {
379: //If module class loader was not added to map it does not contain
380: //any helpset => skip it.
381: continue;
382: }
383: log("", Project.MSG_WARN);
384: log("* * * *", Project.MSG_WARN);
385: log("Parsing module: " + key, Project.MSG_WARN);
386: log("* * * *", Project.MSG_WARN);
387: //Look for *.hs
388: for (Enumeration en = jar.entries(); en
389: .hasMoreElements();) {
390: JarEntry je = (JarEntry) en.nextElement();
391: if (je.getName().endsWith(".hs")) {
392: URLClassLoader moduleClassLoader = (URLClassLoader) classLoaderMap
393: .get(key);
394: URL hsURL = moduleClassLoader.findResource(je
395: .getName());
396: checkHelpSetURL(hsURL, globalClassLoader,
397: moduleClassLoader, classLoaderMap,
398: moduleJar);
399: }
400: }
401: String value = attrs.getValue("Class-Path");
402: if (value != null) {
403: StringTokenizer tok = new StringTokenizer(value);
404: while (tok.hasMoreElements()) {
405: String s = tok.nextToken();
406: File extJar = new File(parent, s);
407: try {
408: jar = new JarFile(extJar);
409: } catch (IOException ex) {
410: ex.printStackTrace();
411: }
412: //Look for *.hs
413: for (Enumeration en = jar.entries(); en
414: .hasMoreElements();) {
415: JarEntry je = (JarEntry) en.nextElement();
416: if (je.getName().endsWith(".hs")) {
417: ClassLoader moduleClassLoader = classLoaderMap
418: .get(key);
419: URL hsURL = moduleClassLoader
420: .getResource(je.getName());
421: checkHelpSetURL(hsURL,
422: globalClassLoader,
423: moduleClassLoader,
424: classLoaderMap, extJar);
425: }
426: }
427: }
428: }
429: }
430: }
431: }
432:
433: private void checkHelpSetURL(URL hsURL,
434: ClassLoader globalClassLoader,
435: ClassLoader moduleClassLoader,
436: java.util.Map classLoaderMap, File extJar) {
437: HelpSet hs = null;
438: try {
439: hs = new HelpSet(moduleClassLoader, hsURL);
440: } catch (HelpSetException ex) {
441: ex.printStackTrace();
442: }
443: javax.help.Map map = hs.getCombinedMap();
444: Enumeration e = map.getAllIDs();
445: Set<URI> okurls = new HashSet<URI>(1000);
446: Set<URI> badurls = new HashSet<URI>(1000);
447: Set<URI> cleanurls = new HashSet<URI>(1000);
448: while (e.hasMoreElements()) {
449: javax.help.Map.ID id = (javax.help.Map.ID) e.nextElement();
450: URL u = null;
451: try {
452: u = id.getURL();
453: } catch (MalformedURLException ex) {
454: log("id:" + id, Project.MSG_WARN);
455: ex.printStackTrace();
456: }
457: if (u == null) {
458: throw new BuildException("Bogus map ID: " + id.id,
459: new Location(extJar.getAbsolutePath()));
460: }
461: log("Checking ID " + id.id, Project.MSG_VERBOSE);
462: try {
463: //System.out.println("CALL OF CheckLinks.scan");
464: List<String> errors = new ArrayList<String>();
465: CheckLinks.scan(this , globalClassLoader,
466: classLoaderMap, id.id, "", new URI(u
467: .toExternalForm()), okurls, badurls,
468: cleanurls, false, false, false, 2, Collections
469: .<Mapper> emptyList(), errors);
470: for (String error : errors) {
471: log(error, Project.MSG_WARN);
472: }
473: //System.out.println("RETURN OF CheckLinks.scan");
474: } catch (URISyntaxException ex) {
475: ex.printStackTrace();
476: } catch (IOException ex) {
477: ex.printStackTrace();
478: }
479: }
480: }
481:
482: /* Unused:
483: private void checkHelpSet(File hsfile) throws Exception {
484: log("Checking helpset: " + hsfile);
485: HelpSet hs = new HelpSet(null, hsfile.toURI().toURL());
486: javax.help.Map map = hs.getCombinedMap();
487: log("Parsed helpset, checking map IDs in TOC/Index navigators...");
488: NavigatorView[] navs = hs.getNavigatorViews();
489: for (int i = 0; i < navs.length; i++) {
490: String name = navs[i].getName();
491: File navfile = new File(hsfile.getParentFile(), (String)navs[i].getParameters().get("data"));
492: if (! navfile.exists()) throw new BuildException("Navigator " + name + " not found", new Location(navfile.getAbsolutePath()));
493: if (navs[i] instanceof IndexView) {
494: log("Checking index navigator " + name, Project.MSG_VERBOSE);
495: IndexView.parse(navfile.toURI().toURL(), hs, Locale.getDefault(), new VerifyTIFactory(hs, map, navfile, false));
496: } else if (navs[i] instanceof TOCView) {
497: log("Checking TOC navigator " + name, Project.MSG_VERBOSE);
498: TOCView.parse(navfile.toURI().toURL(), hs, Locale.getDefault(), new VerifyTIFactory(hs, map, navfile, true));
499: } else {
500: log("Skipping non-TOC/Index view: " + name, Project.MSG_VERBOSE);
501: }
502: }
503: log("Checking for duplicate map IDs...");
504: HelpSet.parse(hsfile.toURI().toURL(), null, new VerifyHSFactory());
505: log("Checking links from help map and between HTML files...");
506: Enumeration e = map.getAllIDs();
507: Set<URI> okurls = new HashSet<URI>(1000);
508: Set<URI> badurls = new HashSet<URI>(1000);
509: Set<URI> cleanurls = new HashSet<URI>(1000);
510: while (e.hasMoreElements()) {
511: javax.help.Map.ID id = (javax.help.Map.ID)e.nextElement();
512: URL u = map.getURLFromID(id);
513: if (u == null) {
514: throw new BuildException("Bogus map ID: " + id.id, new Location(hsfile.getAbsolutePath()));
515: }
516: log("Checking ID " + id.id, Project.MSG_VERBOSE);
517: try {
518: CheckLinks.scan(this, null, null, id.id, "",
519: new URI(u.toExternalForm()), okurls, badurls, cleanurls, false, false, false, 2,
520: Collections.<Mapper>emptyList());
521: } catch (URISyntaxException ex) {
522: ex.printStackTrace();
523: } catch (IOException ex) {
524: ex.printStackTrace();
525: }
526: }
527: }
528: */
529:
530: private final class VerifyTIFactory implements TreeItemFactory {
531:
532: private final HelpSet hs;
533: private final javax.help.Map map;
534: private final File navfile;
535: private final boolean toc;
536:
537: public VerifyTIFactory(HelpSet hs, javax.help.Map map,
538: File navfile, boolean toc) {
539: this .hs = hs;
540: this .map = map;
541: this .navfile = navfile;
542: this .toc = toc;
543: }
544:
545: // The useful method:
546:
547: public TreeItem createItem(String str, Hashtable hashtable,
548: HelpSet helpSet, Locale locale) {
549: String target = (String) hashtable.get("target");
550: if (target != null) {
551: if (!map.isValidID(target, hs)) {
552: log(navfile + ": invalid map ID: " + target,
553: Project.MSG_WARN);
554: } else {
555: log("OK map ID: " + target, Project.MSG_VERBOSE);
556: }
557: }
558: return createItem();
559: }
560:
561: // Filler methods:
562:
563: public java.util.Enumeration listMessages() {
564: return Collections.enumeration(Collections
565: .<String> emptyList());
566: }
567:
568: public void processPI(HelpSet helpSet, String str, String str2) {
569: }
570:
571: public void reportMessage(String str, boolean param) {
572: log(str, param ? Project.MSG_VERBOSE : Project.MSG_WARN);
573: }
574:
575: public void processDOCTYPE(String str, String str1, String str2) {
576: }
577:
578: public void parsingStarted(URL uRL) {
579: }
580:
581: public DefaultMutableTreeNode parsingEnded(
582: DefaultMutableTreeNode defaultMutableTreeNode) {
583: return defaultMutableTreeNode;
584: }
585:
586: public TreeItem createItem() {
587: if (toc) {
588: return new TOCItem();
589: } else {
590: return new IndexItem();
591: }
592: }
593:
594: }
595:
596: private final class VerifyHSFactory extends
597: HelpSet.DefaultHelpSetFactory {
598:
599: private Set<String> ids = new HashSet<String>(1000);
600:
601: public void processMapRef(HelpSet hs, Hashtable attrs) {
602: try {
603: URL map = new URL(hs.getHelpSetURL(), (String) attrs
604: .get("location"));
605: SAXParserFactory factory = SAXParserFactory
606: .newInstance();
607: factory.setValidating(false);
608: factory.setNamespaceAware(false);
609: SAXParser parser = factory.newSAXParser();
610: parser.parse(new InputSource(map.toExternalForm()),
611: new Handler(map.getFile()));
612: } catch (Exception e) {
613: e.printStackTrace();
614: }
615: }
616:
617: private final class Handler extends DefaultHandler {
618:
619: private final String map;
620:
621: public Handler(String map) {
622: this .map = map;
623: }
624:
625: public void startElement(String uri, String lname,
626: String name, Attributes attributes)
627: throws SAXException {
628: if (name.equals("mapID")) {
629: String target = attributes.getValue("target");
630: if (target != null) {
631: if (ids.add(target)) {
632: log("Found map ID: " + target,
633: Project.MSG_DEBUG);
634: } else {
635: log(map + ": duplicated ID: " + target,
636: Project.MSG_WARN);
637: }
638: }
639: }
640: }
641:
642: public InputSource resolveEntity(String pub, String sys)
643: throws SAXException {
644: if (pub
645: .equals("-//Sun Microsystems Inc.//DTD JavaHelp Map Version 1.0//EN")
646: || pub
647: .equals("-//Sun Microsystems Inc.//DTD JavaHelp Map Version 2.0//EN")) {
648: // Ignore.
649: return new InputSource(new ByteArrayInputStream(
650: new byte[0]));
651: } else {
652: return null;
653: }
654: }
655:
656: }
657:
658: }
659:
660: public static class NbDocsStreamHandler extends URLStreamHandler {
661:
662: public static class Factory implements URLStreamHandlerFactory {
663:
664: public URLStreamHandler createURLStreamHandler(
665: String protocol) {
666: if (protocol.equals("nbdocs")) { // NOI18N
667: return new CheckHelpSetsBin.NbDocsStreamHandler();
668: } else {
669: return null;
670: }
671: }
672: }
673:
674: /** Make a URLConnection for nbdocs: URLs.
675: * @param u the URL
676: * @throws IOException if the wrong protocol
677: * @return the connection
678: */
679: protected URLConnection openConnection(URL u)
680: throws IOException {
681: if (u.getProtocol().equals("nbdocs")) { // NOI18N
682: return new NbDocsURLConnection(u);
683: } else {
684: throw new IOException();
685: }
686: }
687:
688: /** A URL connection that reads from the docs classloader.
689: */
690: private static class NbDocsURLConnection extends URLConnection {
691:
692: /** underlying URL connection
693: */
694: private URLConnection real = null;
695:
696: /** any associated exception while handling
697: */
698: private IOException exception = null;
699:
700: /** Make the connection.
701: * @param u URL to connect to
702: */
703: public NbDocsURLConnection(URL u) {
704: super (u);
705: }
706:
707: /** Connect to the URL.
708: * Actually look up and open the underlying connection.
709: * @throws IOException for the usual reasons
710: */
711: public synchronized void connect() throws IOException {
712: if (exception != null) {
713: IOException e = exception;
714: exception = null;
715: throw e;
716: }
717: if (!connected) {
718: real.connect();
719: connected = true;
720: }
721: }
722:
723: /** Maybe connect, if not keep track of the problem.
724: */
725: private void tryToConnect() {
726: if (connected || exception != null)
727: return;
728: try {
729: connect();
730: } catch (IOException ioe) {
731: exception = ioe;
732: }
733: }
734:
735: /** Get a URL header.
736: * @param n index of the header
737: * @return the header value
738: */
739: public String getHeaderField(int n) {
740: tryToConnect();
741: if (connected)
742: return real.getHeaderField(n);
743: else
744: return null;
745: }
746:
747: /** Get the name of a header.
748: * @param n the index
749: * @return the header name
750: */
751: public String getHeaderFieldKey(int n) {
752: tryToConnect();
753: if (connected)
754: return real.getHeaderFieldKey(n);
755: else
756: return null;
757: }
758:
759: /** Get a header by name.
760: * @param key the header name
761: * @return the value
762: */
763: public String getHeaderField(String key) {
764: tryToConnect();
765: if (connected)
766: return real.getHeaderField(key);
767: else
768: return null;
769: }
770:
771: /** Get an input stream on the connection.
772: * @throws IOException for the usual reasons
773: * @return a stream to the object
774: */
775: public InputStream getInputStream() throws IOException {
776: connect();
777: return real.getInputStream();
778: }
779:
780: /** Get an output stream on the object.
781: * @throws IOException for the usual reasons
782: * @return an output stream writing to it
783: */
784: public OutputStream getOutputStream() throws IOException {
785: connect();
786: return real.getOutputStream();
787: }
788:
789: /** Get the type of the content.
790: * @return the MIME type
791: */
792: public String getContentType() {
793: tryToConnect();
794: if (connected)
795: return real.getContentType();
796: else
797: return "application/octet-stream"; // NOI18N
798: }
799:
800: /** Get the length of content.
801: * @return the length in bytes
802: */
803: public int getContentLength() {
804: tryToConnect();
805: if (connected)
806: return real.getContentLength();
807: else
808: return 0;
809: }
810:
811: }
812:
813: }
814:
815: }
|