/** * Resolves a reference to a local or remote file or element. If the link refers to an element in * the current document, this method returns that element. If the link refers to a remote * document, this method will initiate asynchronous retrieval of the document, and return a URL of * the downloaded document in the file cache, if it is available locally. If the link identifies a * COLLADA document, the document will be returned as a parsed ColladaRoot. * * @param link the address of the document or element to resolve. This may be a full URL, a URL * fragment that identifies an element in the current document ("#myElement"), or a URL and a * fragment identifier ("http://server.com/model.dae#myElement"). * @return the requested element, or null if the element is not found. * @throws IllegalArgumentException if the address is null. */ public Object resolveReference(String link) { if (link == null) { String message = Logging.getMessage("nullValue.DocumentSourceIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } try { String[] linkParts = link.split("#"); String linkBase = linkParts[0]; String linkRef = linkParts.length > 1 ? linkParts[1] : null; // See if it's a reference to an internal element. if (WWUtil.isEmpty(linkBase) && !WWUtil.isEmpty(linkRef)) return this.getItemByID(linkRef); // Interpret the path relative to the current document. String path = this.getSupportFilePath(linkBase); if (path == null) path = linkBase; // See if it's an already found and parsed COLLADA file. Object o = WorldWind.getSessionCache().get(path); if (o != null && o instanceof ColladaRoot) return linkRef != null ? ((ColladaRoot) o).getItemByID(linkRef) : o; URL url = WWIO.makeURL(path); if (url == null) { // See if the reference can be resolved to a local file. o = this.resolveLocalReference(path, linkRef); } // If we didn't find a local file, treat it as a remote reference. if (o == null) o = this.resolveRemoteReference(path, linkRef); if (o != null) return o; // If the reference was not resolved as a remote reference, look for a local element // identified by the // reference string. This handles the case of malformed internal references that omit the # // sign at the // beginning of the reference. return this.getItemByID(link); } catch (Exception e) { String message = Logging.getMessage("generic.UnableToResolveReference", link); Logging.logger().warning(message); } return null; }
/** * Build the resource map from the KML Model's <i>ResourceMap</i> element. * * @param model Model from which to create the resource map. * @return Map that relates relative paths in the COLLADA document to paths relative to the KML * document. */ protected Map<String, String> createResourceMap(KMLModel model) { Map<String, String> map = new HashMap<String, String>(); KMLResourceMap resourceMap = model.getResourceMap(); if (resourceMap == null) return Collections.emptyMap(); for (KMLAlias alias : resourceMap.getAliases()) { if (alias != null && !WWUtil.isEmpty(alias.getSourceRef()) && !WWUtil.isEmpty(alias.getTargetHref())) { map.put(alias.getSourceRef(), alias.getTargetHref()); } } return map.size() > 0 ? map : Collections.<String, String>emptyMap(); }
/** * Unzips the sole entry in the specified zip file, and saves it in a temporary directory, and * returns a File to the temporary location. * * @param path the path to the source file. * @param suffix the suffix to give the temp file. * @return a {@link File} for the temp file. * @throws IllegalArgumentException if the <code>path</code> is <code>null</code> or empty. */ public static File unzipAndSaveToTempFile(String path, String suffix) { if (WWUtil.isEmpty(path)) { String message = Logging.getMessage("nullValue.PathIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } InputStream stream = null; try { stream = WWIO.openStream(path); ByteBuffer buffer = WWIO.readStreamToBuffer(stream); File file = WWIO.saveBufferToTempFile(buffer, WWIO.getFilename(path)); buffer = WWIO.readZipEntryToBuffer(file, null); return WWIO.saveBufferToTempFile(buffer, suffix); } catch (Exception e) { e.printStackTrace(); } finally { WWIO.closeStream(stream, path); } return null; }
/** * Thread's off a task to determine whether the resource is local or remote and then retrieves it * either from disk cache or a remote server. * * @param dc the current draw context. */ protected void requestResource(DrawContext dc) { if (WorldWind.getTaskService().isFull()) return; KMLLink link = this.model.getLink(); if (link == null) return; String address = link.getAddress(dc); if (address != null) address = address.trim(); if (WWUtil.isEmpty(address)) return; WorldWind.getTaskService().addTask(new RequestTask(this, address)); }
/** * Resolves a reference to a remote element identified by address and identifier, where {@code * linkBase} identifies a remote document, and {@code linkRef} is the id of the desired element. * This method retrieves resources asynchronously using the {@link * gov.nasa.worldwind.cache.FileStore}. * * <p>The return value is null if the file is not yet available in the FileStore. If {@code * linkBase} refers to a COLLADA file and {@code linkRef} is non-null, the return value is the * element identified by {@code linkRef}. If {@code linkBase} refers to a COLLADA file and {@code * linkRef} is null, the return value is a parsed {@link ColladaRoot} for the COLLADA file * identified by {@code linkBase}. Otherwise the return value is a {@link URL} to the file in the * file cache. * * @param linkBase the address of the document containing the requested element. * @param linkRef the element's identifier. * @return URL to the requested file, parsed ColladaRoot, or COLLADA element. Returns null if the * document is not yet available in the FileStore. * @throws IllegalArgumentException if the {@code linkBase} is null. */ public Object resolveRemoteReference(String linkBase, String linkRef) { if (linkBase == null) { String message = Logging.getMessage("nullValue.DocumentSourceIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } try { // See if it's in the cache. If not, requestFile will start another thread to retrieve it and // return null. URL url = WorldWind.getDataFileStore().requestFile(linkBase); if (url == null) return null; // It's in the cache. If it's a COLLADA file try to parse it so we can search for the // specified reference. // If it's not COLLADA, just return the url for the cached file. String contentType = WorldWind.getDataFileStore().getContentType(linkBase); if (contentType == null) { String suffix = WWIO.getSuffix(linkBase.split(";")[0]); // strip of trailing garbage if (!WWUtil.isEmpty(suffix)) contentType = WWIO.makeMimeTypeForSuffix(suffix); } if (!this.canParseContentType(contentType)) return url; // If the file is a COLLADA document, attempt to open it. We can't open it as a File with // createAndParse // because the ColladaRoot that will be created needs to have the remote address in order to // resolve any // relative references within it. ColladaRoot refRoot = this.parseCachedColladaFile(url, linkBase); // Add the parsed file to the session cache so it doesn't have to be parsed again. WorldWind.getSessionCache().put(linkBase, refRoot); // Now check the newly opened COLLADA file for the referenced item, if a reference was // specified. if (linkRef != null) return refRoot.getItemByID(linkRef); else return refRoot; } catch (Exception e) { String message = Logging.getMessage("generic.UnableToResolveReference", linkBase + "/" + linkRef); Logging.logger().warning(message); return null; } }