PageRenderTime 59ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/netbeans-7.3/nbbuild/antsrc/org/netbeans/nbbuild/CheckHelpSetsBin.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 645 lines | 347 code | 35 blank | 263 comment | 69 complexity | 995775103f1fad06c4881d3d9572dd5a MD5 | raw file
  1. /*
  2. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  3. *
  4. * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
  5. *
  6. * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  7. * Other names may be trademarks of their respective owners.
  8. *
  9. * The contents of this file are subject to the terms of either the GNU
  10. * General Public License Version 2 only ("GPL") or the Common
  11. * Development and Distribution License("CDDL") (collectively, the
  12. * "License"). You may not use this file except in compliance with the
  13. * License. You can obtain a copy of the License at
  14. * http://www.netbeans.org/cddl-gplv2.html
  15. * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  16. * specific language governing permissions and limitations under the
  17. * License. When distributing the software, include this License Header
  18. * Notice in each file and include the License file at
  19. * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
  20. * particular file as subject to the "Classpath" exception as provided
  21. * by Oracle in the GPL Version 2 section of the License file that
  22. * accompanied this code. If applicable, add the following below the
  23. * License Header, with the fields enclosed by brackets [] replaced by
  24. * your own identifying information:
  25. * "Portions Copyrighted [year] [name of copyright owner]"
  26. *
  27. * Contributor(s):
  28. *
  29. * The Original Software is NetBeans. The Initial Developer of the Original
  30. * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
  31. * Microsystems, Inc. All Rights Reserved.
  32. *
  33. * If you wish your version of this file to be governed by only the CDDL
  34. * or only the GPL Version 2, indicate your decision by adding
  35. * "[Contributor] elects to include this software in this distribution
  36. * under the [CDDL or GPL Version 2] license." If you do not indicate a
  37. * single choice of license, a recipient has the option to distribute
  38. * your version of this file under either the CDDL, the GPL Version 2 or
  39. * to extend the choice of license to its licensees as provided above.
  40. * However, if you add GPL Version 2 code and therefore, elected the GPL
  41. * Version 2 license, then the option applies only if the new code is
  42. * made subject to such option by the copyright holder.
  43. */
  44. // See #13931.
  45. package org.netbeans.nbbuild;
  46. import java.io.File;
  47. import java.io.FileNotFoundException;
  48. import java.io.IOException;
  49. import java.io.InputStream;
  50. import java.io.OutputStream;
  51. import java.io.StringReader;
  52. import java.net.MalformedURLException;
  53. import java.net.URI;
  54. import java.net.URISyntaxException;
  55. import java.net.URL;
  56. import java.net.URLClassLoader;
  57. import java.net.URLConnection;
  58. import java.net.URLStreamHandler;
  59. import java.net.URLStreamHandlerFactory;
  60. import java.util.ArrayList;
  61. import java.util.Arrays;
  62. import java.util.Collections;
  63. import java.util.Enumeration;
  64. import java.util.HashSet;
  65. import java.util.List;
  66. import java.util.Map;
  67. import java.util.Set;
  68. import java.util.TreeMap;
  69. import java.util.jar.JarFile;
  70. import java.util.jar.Manifest;
  71. import javax.help.HelpSet;
  72. import javax.help.HelpSetException;
  73. import org.apache.tools.ant.BuildException;
  74. import org.apache.tools.ant.FileScanner;
  75. import org.apache.tools.ant.Project;
  76. import org.apache.tools.ant.Task;
  77. import org.apache.tools.ant.types.FileSet;
  78. import org.apache.tools.ant.types.Mapper;
  79. import org.w3c.dom.Document;
  80. import org.w3c.dom.Element;
  81. import org.w3c.dom.Node;
  82. import org.w3c.dom.NodeList;
  83. import org.xml.sax.InputSource;
  84. import org.xml.sax.SAXException;
  85. /** Task to check various aspects of JavaHelp helpsets.
  86. * <ol>
  87. * <li>General parsability as far as JavaHelp is concerned.
  88. * <li>Map IDs are not duplicated.
  89. * <li>Map IDs point to real HTML files (and anchors where specified).
  90. * <li>TOC/Index navigators refer to real map IDs.
  91. * <li>HTML links in reachable HTML files point to valid places (including anchors).
  92. * </ol>
  93. * @author Jesse Glick, Marek Slama
  94. */
  95. public class CheckHelpSetsBin extends Task {
  96. private List<FileSet> filesets = new ArrayList<FileSet>();
  97. private Set<String> excludedModulesSet;
  98. /**
  99. * Adds a set of module JARs. Class-Path extensions (including separate doc JARs) should not be included.
  100. */
  101. public void addFileset(FileSet fs) {
  102. filesets.add(fs);
  103. }
  104. private URLClassLoader createGlobalClassLoader(File dir, String[] files) throws MalformedURLException {
  105. URL[] globalClassPath = new URL[files.length];
  106. for (int i = 0; i < files.length; i++) {
  107. globalClassPath[i] = new File(dir, files[i]).toURI().toURL();
  108. }
  109. return new URLClassLoader(globalClassPath, ClassLoader.getSystemClassLoader().getParent(), new NbDocsStreamHandler.Factory());
  110. }
  111. private Map<String,URLClassLoader> createClassLoaderMap(File dir, String[] files) throws IOException {
  112. Map<String,URLClassLoader> m = new TreeMap<String,URLClassLoader>();
  113. for (int i = 0; i < files.length; i++) {
  114. File moduleJar = new File(dir, files[i]);
  115. Manifest manifest;
  116. JarFile jar = new JarFile(moduleJar);
  117. try {
  118. manifest = jar.getManifest();
  119. } finally {
  120. jar.close();
  121. }
  122. if (manifest == null) {
  123. log(moduleJar + " has no manifest", Project.MSG_WARN);
  124. continue;
  125. }
  126. String codename = JarWithModuleAttributes.extractCodeName(manifest.getMainAttributes());
  127. if (codename == null) {
  128. log(moduleJar + " is not a module", Project.MSG_WARN);
  129. continue;
  130. }
  131. m.put(codename.replaceFirst("/[0-9]+$", ""), new URLClassLoader(new URL[] {moduleJar.toURI().toURL()}, ClassLoader.getSystemClassLoader().getParent(), new NbDocsStreamHandler.Factory()));
  132. }
  133. return m;
  134. }
  135. private Set<String> parseExcludeModulesProperty (String prop) {
  136. if (prop == null) {
  137. return Collections.emptySet();
  138. }
  139. return new HashSet<String>(Arrays.asList(prop.split(",")));
  140. }
  141. public @Override void execute() throws BuildException {
  142. String p = getProject().getProperty("javahelpbin.exclude.modules");
  143. excludedModulesSet = parseExcludeModulesProperty(p);
  144. for (FileSet fs : filesets) {
  145. FileScanner scanner = fs.getDirectoryScanner(getProject());
  146. File dir = scanner.getBasedir();
  147. String[] files = scanner.getIncludedFiles();
  148. URLClassLoader globalClassLoader;
  149. Map<String,URLClassLoader> classLoaderMap;
  150. try {
  151. globalClassLoader = createGlobalClassLoader(dir, files);
  152. classLoaderMap = createClassLoaderMap(dir, files);
  153. NbDocsStreamHandler.NbDocsURLConnection.globalClassLoader.set(globalClassLoader);
  154. NbDocsStreamHandler.NbDocsURLConnection.classLoaderMap.set(classLoaderMap);
  155. CheckLinks.handlerFactory.set(new NbDocsStreamHandler.Factory());
  156. for (Map.Entry<String,URLClassLoader> entry : classLoaderMap.entrySet()) {
  157. String cnb = entry.getKey();
  158. if (excludedModulesSet.contains(cnb)) {
  159. log("skipping module: " + cnb, Project.MSG_INFO);
  160. continue;
  161. }
  162. URLClassLoader l = entry.getValue();
  163. Manifest m;
  164. InputStream is = l.getResourceAsStream("META-INF/MANIFEST.MF");
  165. if (is != null) {
  166. try {
  167. m = new Manifest(is);
  168. } finally {
  169. is.close();
  170. }
  171. } else {
  172. log("No manifest in " + Arrays.toString(l.getURLs()), Project.MSG_WARN);
  173. continue;
  174. }
  175. for (String resource : new String[] {m.getMainAttributes().getValue("OpenIDE-Module-Layer"), "META-INF/generated-layer.xml"}) {
  176. if (resource == null) {
  177. continue;
  178. }
  179. URL layer = l.getResource(resource);
  180. if (layer == null) {
  181. log("No layer " + resource, Project.MSG_VERBOSE);
  182. continue;
  183. }
  184. Document doc;
  185. try {
  186. doc = XMLUtil.parse(new InputSource(layer.toString()), false, false, XMLUtil.rethrowHandler(), XMLUtil.nullResolver());
  187. } catch (SAXException x) {
  188. log("Could not parse " + layer, x, Project.MSG_WARN);
  189. continue;
  190. }
  191. for (Element services : XMLUtil.findSubElements(doc.getDocumentElement())) {
  192. if (!services.getTagName().equals("folder") || !services.getAttribute("name").equals("Services")) {
  193. continue;
  194. }
  195. for (Element javahelp : XMLUtil.findSubElements(services)) {
  196. if (!javahelp.getTagName().equals("folder") || !javahelp.getAttribute("name").equals("JavaHelp")) {
  197. continue;
  198. }
  199. JAVAHELP: for (Element registration : XMLUtil.findSubElements(javahelp)) {
  200. if (!registration.getTagName().equals("file")) {
  201. continue;
  202. }
  203. InputSource input = null;
  204. String url = registration.getAttribute("url");
  205. if (!url.isEmpty()) {
  206. input = new InputSource(new URL(layer, url).toString());
  207. } else {
  208. NodeList nl = registration.getChildNodes();
  209. for (int i = 0; i < nl.getLength(); i++) {
  210. if (nl.item(i).getNodeType() == Node.CDATA_SECTION_NODE) {
  211. if (input == null) {
  212. input = new InputSource(new StringReader(nl.item(i).getNodeValue()));
  213. } else {
  214. log("Multiple content for " + registration.getAttribute("name") + " in " + layer, Project.MSG_WARN);
  215. continue JAVAHELP;
  216. }
  217. }
  218. }
  219. if (input == null) {
  220. log("No content for " + registration.getAttribute("name") + " in " + layer, Project.MSG_WARN);
  221. }
  222. }
  223. Document doc2;
  224. try {
  225. doc2 = XMLUtil.parse(input, false, false, XMLUtil.rethrowHandler(), XMLUtil.nullResolver());
  226. } catch (SAXException x) {
  227. log("Could not parse " + registration.getAttribute("name") + " in " + layer, x, Project.MSG_WARN);
  228. continue;
  229. }
  230. URI helpsetref = URI.create(doc2.getDocumentElement().getAttribute("url"));
  231. if ("nbdocs".equals(helpsetref.getScheme()) && helpsetref.getAuthority() == null) {
  232. try {
  233. helpsetref = new URI(helpsetref.getScheme(), cnb, helpsetref.getPath(), helpsetref.getQuery(), helpsetref.getFragment());
  234. } catch (URISyntaxException x) {
  235. throw new BuildException(x);
  236. }
  237. }
  238. log("checking: " + helpsetref, Project.MSG_INFO);
  239. checkHelpSetURL(CheckLinks.toURL(helpsetref), globalClassLoader, l, classLoaderMap, cnb);
  240. }
  241. }
  242. }
  243. }
  244. }
  245. } catch (IOException x) {
  246. throw new BuildException(x);
  247. } finally {
  248. NbDocsStreamHandler.NbDocsURLConnection.globalClassLoader.set(null);
  249. NbDocsStreamHandler.NbDocsURLConnection.classLoaderMap.set(null);
  250. CheckLinks.handlerFactory.set(null);
  251. }
  252. }
  253. }
  254. private void checkHelpSetURL
  255. (URL hsURL, ClassLoader globalClassLoader, ClassLoader moduleClassLoader, Map<String,URLClassLoader> classLoaderMap, String cnb) {
  256. HelpSet hs = null;
  257. try {
  258. hs = new HelpSet(moduleClassLoader, hsURL);
  259. } catch (HelpSetException ex) {
  260. throw new BuildException("Failed to parse " + hsURL + ": " + ex, ex, getLocation());
  261. }
  262. javax.help.Map map = hs.getCombinedMap();
  263. Enumeration<?> e = map.getAllIDs();
  264. Set<URI> okurls = new HashSet<URI>(1000);
  265. Set<URI> badurls = new HashSet<URI>(1000);
  266. Set<URI> cleanurls = new HashSet<URI>(1000);
  267. while (e.hasMoreElements()) {
  268. javax.help.Map.ID id = (javax.help.Map.ID)e.nextElement();
  269. URL u = null;
  270. try {
  271. u = id.getURL();
  272. } catch (MalformedURLException ex) {
  273. log("id:" + id, Project.MSG_WARN);
  274. ex.printStackTrace();
  275. }
  276. if (u == null) {
  277. throw new BuildException("Bogus map ID: " + id.id + " in: " + cnb);
  278. }
  279. log("Checking ID " + id.id, Project.MSG_VERBOSE);
  280. try {
  281. //System.out.println("CALL OF CheckLinks.scan");
  282. List<String> errors = new ArrayList<String>();
  283. CheckLinks.scan(this, globalClassLoader, classLoaderMap, id.id, "",
  284. new URI(u.toExternalForm()), okurls, badurls, cleanurls, false, false, false, 2,
  285. Collections.<Mapper>emptyList(), errors);
  286. for (String error : errors) {
  287. log(error, Project.MSG_WARN);
  288. }
  289. //System.out.println("RETURN OF CheckLinks.scan");
  290. } catch (URISyntaxException ex) {
  291. ex.printStackTrace();
  292. } catch (IOException ex) {
  293. ex.printStackTrace();
  294. }
  295. }
  296. }
  297. /* Unused:
  298. private void checkHelpSet(File hsfile) throws Exception {
  299. log("Checking helpset: " + hsfile);
  300. HelpSet hs = new HelpSet(null, hsfile.toURI().toURL());
  301. javax.help.Map map = hs.getCombinedMap();
  302. log("Parsed helpset, checking map IDs in TOC/Index navigators...");
  303. NavigatorView[] navs = hs.getNavigatorViews();
  304. for (int i = 0; i < navs.length; i++) {
  305. String name = navs[i].getName();
  306. File navfile = new File(hsfile.getParentFile(), (String)navs[i].getParameters().get("data"));
  307. if (! navfile.exists()) throw new BuildException("Navigator " + name + " not found", new Location(navfile.getAbsolutePath()));
  308. if (navs[i] instanceof IndexView) {
  309. log("Checking index navigator " + name, Project.MSG_VERBOSE);
  310. IndexView.parse(navfile.toURI().toURL(), hs, Locale.getDefault(), new VerifyTIFactory(hs, map, navfile, false));
  311. } else if (navs[i] instanceof TOCView) {
  312. log("Checking TOC navigator " + name, Project.MSG_VERBOSE);
  313. TOCView.parse(navfile.toURI().toURL(), hs, Locale.getDefault(), new VerifyTIFactory(hs, map, navfile, true));
  314. } else {
  315. log("Skipping non-TOC/Index view: " + name, Project.MSG_VERBOSE);
  316. }
  317. }
  318. log("Checking for duplicate map IDs...");
  319. HelpSet.parse(hsfile.toURI().toURL(), null, new VerifyHSFactory());
  320. log("Checking links from help map and between HTML files...");
  321. Enumeration e = map.getAllIDs();
  322. Set<URI> okurls = new HashSet<URI>(1000);
  323. Set<URI> badurls = new HashSet<URI>(1000);
  324. Set<URI> cleanurls = new HashSet<URI>(1000);
  325. while (e.hasMoreElements()) {
  326. javax.help.Map.ID id = (javax.help.Map.ID)e.nextElement();
  327. URL u = map.getURLFromID(id);
  328. if (u == null) {
  329. throw new BuildException("Bogus map ID: " + id.id, new Location(hsfile.getAbsolutePath()));
  330. }
  331. log("Checking ID " + id.id, Project.MSG_VERBOSE);
  332. try {
  333. CheckLinks.scan(this, null, null, id.id, "",
  334. new URI(u.toExternalForm()), okurls, badurls, cleanurls, false, false, false, 2,
  335. Collections.<Mapper>emptyList());
  336. } catch (URISyntaxException ex) {
  337. ex.printStackTrace();
  338. } catch (IOException ex) {
  339. ex.printStackTrace();
  340. }
  341. }
  342. }
  343. private final class VerifyTIFactory implements TreeItemFactory {
  344. private final HelpSet hs;
  345. private final javax.help.Map map;
  346. private final File navfile;
  347. private final boolean toc;
  348. public VerifyTIFactory(HelpSet hs, javax.help.Map map, File navfile, boolean toc) {
  349. this.hs = hs;
  350. this.map = map;
  351. this.navfile = navfile;
  352. this.toc = toc;
  353. }
  354. // The useful method:
  355. public TreeItem createItem(String str, Hashtable hashtable, HelpSet helpSet, Locale locale) {
  356. String target = (String)hashtable.get("target");
  357. if (target != null) {
  358. if (! map.isValidID(target, hs)) {
  359. log(navfile + ": invalid map ID: " + target, Project.MSG_WARN);
  360. } else {
  361. log("OK map ID: " + target, Project.MSG_VERBOSE);
  362. }
  363. }
  364. return createItem();
  365. }
  366. // Filler methods:
  367. public java.util.Enumeration listMessages() {
  368. return Collections.enumeration(Collections.<String>emptyList());
  369. }
  370. public void processPI(HelpSet helpSet, String str, String str2) {
  371. }
  372. public void reportMessage(String str, boolean param) {
  373. log(str, param ? Project.MSG_VERBOSE : Project.MSG_WARN);
  374. }
  375. public void processDOCTYPE(String str, String str1, String str2) {
  376. }
  377. public void parsingStarted(URL uRL) {
  378. }
  379. public DefaultMutableTreeNode parsingEnded(DefaultMutableTreeNode defaultMutableTreeNode) {
  380. return defaultMutableTreeNode;
  381. }
  382. public TreeItem createItem() {
  383. if (toc) {
  384. return new TOCItem();
  385. } else {
  386. return new IndexItem();
  387. }
  388. }
  389. }
  390. private final class VerifyHSFactory extends HelpSet.DefaultHelpSetFactory {
  391. private Set<String> ids = new HashSet<String>(1000);
  392. public void processMapRef(HelpSet hs, Hashtable attrs) {
  393. try {
  394. URL map = new URL(hs.getHelpSetURL(), (String)attrs.get("location"));
  395. SAXParserFactory factory = SAXParserFactory.newInstance();
  396. factory.setValidating(false);
  397. factory.setNamespaceAware(false);
  398. SAXParser parser = factory.newSAXParser();
  399. parser.parse(new InputSource(map.toExternalForm()), new Handler(map.getFile()));
  400. } catch (Exception e) {
  401. e.printStackTrace();
  402. }
  403. }
  404. private final class Handler extends DefaultHandler {
  405. private final String map;
  406. public Handler(String map) {
  407. this.map = map;
  408. }
  409. public void startElement(String uri, String lname, String name, Attributes attributes) throws SAXException {
  410. if (name.equals("mapID")) {
  411. String target = attributes.getValue("target");
  412. if (target != null) {
  413. if (ids.add(target)) {
  414. log("Found map ID: " + target, Project.MSG_DEBUG);
  415. } else {
  416. log(map + ": duplicated ID: " + target, Project.MSG_WARN);
  417. }
  418. }
  419. }
  420. }
  421. public InputSource resolveEntity(String pub, String sys) throws SAXException {
  422. if (pub.equals("-//Sun Microsystems Inc.//DTD JavaHelp Map Version 1.0//EN") ||
  423. pub.equals("-//Sun Microsystems Inc.//DTD JavaHelp Map Version 2.0//EN")) {
  424. // Ignore.
  425. return new InputSource(new ByteArrayInputStream(new byte[0]));
  426. } else {
  427. return null;
  428. }
  429. }
  430. }
  431. }
  432. */
  433. private static class NbDocsStreamHandler extends URLStreamHandler {
  434. static class Factory implements URLStreamHandlerFactory {
  435. public URLStreamHandler createURLStreamHandler(String protocol) {
  436. if (protocol.equals("nbdocs")) { // NOI18N
  437. return new CheckHelpSetsBin.NbDocsStreamHandler();
  438. } else {
  439. return null;
  440. }
  441. }
  442. }
  443. /** Make a URLConnection for nbdocs: URLs.
  444. * @param u the URL
  445. * @throws IOException if the wrong protocol
  446. * @return the connection
  447. */
  448. protected URLConnection openConnection(URL u) throws IOException {
  449. if (u.getProtocol().equals("nbdocs")) { // NOI18N
  450. return new NbDocsURLConnection(u);
  451. } else {
  452. throw new IOException();
  453. }
  454. }
  455. /** A URL connection that reads from the docs classloader.
  456. */
  457. static class NbDocsURLConnection extends URLConnection {
  458. static ThreadLocal<URLClassLoader> globalClassLoader = new ThreadLocal<URLClassLoader>();
  459. static ThreadLocal<Map<String,URLClassLoader>> classLoaderMap = new ThreadLocal<Map<String,URLClassLoader>>();
  460. /** underlying URL connection
  461. */
  462. private URLConnection real = null;
  463. /** any associated exception while handling
  464. */
  465. private IOException exception = null;
  466. /** Make the connection.
  467. * @param u URL to connect to
  468. */
  469. public NbDocsURLConnection(URL u) {
  470. super(u);
  471. }
  472. /** Connect to the URL.
  473. * Actually look up and open the underlying connection.
  474. * @throws IOException for the usual reasons
  475. */
  476. public synchronized void connect() throws IOException {
  477. tryToConnect();
  478. if (exception != null) {
  479. exception.printStackTrace();//XXX
  480. throw exception;
  481. }
  482. }
  483. /** Maybe connect, if not keep track of the problem.
  484. */
  485. private synchronized void tryToConnect() {
  486. if (connected || exception != null) {
  487. return;
  488. }
  489. try {
  490. URLClassLoader l;
  491. String cnb = url.getHost();
  492. if (cnb.isEmpty()) {
  493. l = globalClassLoader.get();
  494. } else {
  495. l = classLoaderMap.get().get(cnb);
  496. if (l == null) {
  497. throw new IOException("no loader for " + cnb);
  498. }
  499. }
  500. String path = url.getPath().substring(1);
  501. URL u = l.getResource(path);
  502. if (u == null) {
  503. throw new FileNotFoundException(path + " in " + Arrays.toString(l.getURLs()));
  504. }
  505. real = u.openConnection();
  506. real.connect();
  507. connected = true;
  508. } catch (IOException ioe) {
  509. exception = ioe;
  510. }
  511. }
  512. /** Get a URL header.
  513. * @param n index of the header
  514. * @return the header value
  515. */
  516. public @Override String getHeaderField(int n) {
  517. tryToConnect();
  518. if (connected) {
  519. return real.getHeaderField(n);
  520. } else {
  521. return null;
  522. }
  523. }
  524. /** Get the name of a header.
  525. * @param n the index
  526. * @return the header name
  527. */
  528. public @Override String getHeaderFieldKey(int n) {
  529. tryToConnect();
  530. if (connected) {
  531. return real.getHeaderFieldKey(n);
  532. } else {
  533. return null;
  534. }
  535. }
  536. /** Get a header by name.
  537. * @param key the header name
  538. * @return the value
  539. */
  540. public @Override String getHeaderField(String key) {
  541. tryToConnect();
  542. if (connected) {
  543. return real.getHeaderField(key);
  544. } else {
  545. return null;
  546. }
  547. }
  548. /** Get an input stream on the connection.
  549. * @throws IOException for the usual reasons
  550. * @return a stream to the object
  551. */
  552. public @Override InputStream getInputStream() throws IOException {
  553. connect();
  554. return real.getInputStream();
  555. }
  556. /** Get an output stream on the object.
  557. * @throws IOException for the usual reasons
  558. * @return an output stream writing to it
  559. */
  560. public @Override OutputStream getOutputStream() throws IOException {
  561. connect();
  562. return real.getOutputStream();
  563. }
  564. /** Get the type of the content.
  565. * @return the MIME type
  566. */
  567. public @Override String getContentType() {
  568. tryToConnect();
  569. if (connected) {
  570. return real.getContentType();
  571. } else {
  572. return "application/octet-stream";
  573. }
  574. }
  575. /** Get the length of content.
  576. * @return the length in bytes
  577. */
  578. public @Override int getContentLength() {
  579. tryToConnect();
  580. if (connected) {
  581. return real.getContentLength();
  582. } else {
  583. return 0;
  584. }
  585. }
  586. }
  587. }
  588. }