/* * $Id$ * This file is a part of the Arakhne Foundation Classes, http://www.arakhne.org/afc * * Copyright (c) 2000-2012 Stephane GALLAND. * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports, * Universite de Technologie de Belfort-Montbeliard. * Copyright (c) 2013-2016 The original authors, and other authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.arakhne.afc.inputoutput.xml; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.arakhne.afc.vmutil.FileSystem; import org.arakhne.afc.vmutil.Resources; import org.arakhne.afc.vmutil.URISchemeType; /** A class that permits to load an external XML resource. * * <p>It is based on the systemId and tries to find the file * described in the systemId. To do this it tries the following * cases in turn and replies the corresponding resource: * <ol> * <li>if {@code systemId} is a local file ie, an {@code file://} URL * with or without the URL scheme, if the filename is absolute, * and if the file exists then the file's content is replied.<br> * Example: {@code file:///tmp/mydtd-1.0.dtd}</li> * <li>if {@code systemId} is a local file ie, an {@code file://} URL * with or without the URL scheme, if the filename is relative, * and if a file located relatively to the current directory of * the XML file exists then the file's content is replied.<br> * Example: {@code mydirectory/mydtd-1.0.dtd}</li> * <li>if {@code systemId} is a local file ie, an {@code file://} URL * with or without the URL scheme, and if the filename is absolute then * the {@link Class#getResource(String)} is invoked with the * {@code systemId} as parameter.<br> * Example: {@code /fr/utbm/set/package/mydtd-1.0.dtd}</li> * <li>if a {@code searchPath} was specified to the constructor and if * a file located relatively to this {@code searchPath} exists, then * the file's content is replied.</li> * </ol> * * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ * @since 14.0 */ public class DefaultXMLEntityResolver implements EntityResolver { private final URL searchPath; private boolean emptyExternalResource; /** Constructor. */ public DefaultXMLEntityResolver() { this.searchPath = null; this.emptyExternalResource = false; } /** * @param searchPath is the directory which corresponds to a search path. * @throws MalformedURLException if the file cannot be converted to an URL. */ public DefaultXMLEntityResolver(File searchPath) throws MalformedURLException { this(searchPath.toURI().toURL()); } /** * @param searchPath is the directory which corresponds to a search path. */ public DefaultXMLEntityResolver(URL searchPath) { this.searchPath = searchPath; this.emptyExternalResource = false; } /** * @param assumeEmptyExternalResource if <code>true</code> this entity resolver * replies an empty input source when it can't find an external resource. If <code>false</code> * this resolver will ask to the default XML resolver to find the external resource. */ public DefaultXMLEntityResolver(boolean assumeEmptyExternalResource) { this.searchPath = null; this.emptyExternalResource = assumeEmptyExternalResource; } /** * @param searchPath is the directory which corresponds to a search path. * @param assumeEmptyExternalResource if <code>true</code> this entity resolver * replies an empty input source when it can't find an external resource. If <code>false</code> * this resolver will ask to the default XML resolver to find the external resource. * @throws MalformedURLException if the file cannot be converted to an URL. */ public DefaultXMLEntityResolver(File searchPath, boolean assumeEmptyExternalResource) throws MalformedURLException { this(searchPath.toURI().toURL(), assumeEmptyExternalResource); } /** * @param searchPath is the directory which corresponds to a search path. * @param assumeEmptyExternalResource if <code>true</code> this entity resolver * replies an empty input source when it can't find an external resource. If <code>false</code> * this resolver will ask to the default XML resolver to find the external resource. */ public DefaultXMLEntityResolver(URL searchPath, boolean assumeEmptyExternalResource) { this.searchPath = searchPath; this.emptyExternalResource = assumeEmptyExternalResource; } @SuppressWarnings("resource") private static InputSource getInputSourceFromSystemUrl(URL systemUrl) { if (systemUrl != null) { try { final InputStream systemIdStream = systemUrl.openStream(); if (systemIdStream != null) { return new InputSource(systemIdStream); } } catch (Exception e) { // } } return null; } @SuppressWarnings("resource") private static InputSource getInputSourceFromResources(URL systemUrl, String systemId, URL containerPath) { if (systemUrl != null && URISchemeType.getSchemeType(systemUrl).isFileBasedScheme()) { final String file = systemUrl.getPath(); final InputStream systemIdStream = Resources.getResourceAsStream(file); if (systemIdStream != null) { return new InputSource(systemIdStream); } } else { String id = systemId; if (containerPath != null) { id = FileSystem.join(containerPath, systemId).getPath(); } final InputStream systemIdStream = Resources.getResourceAsStream(id); if (systemIdStream != null) { return new InputSource(systemIdStream); } } return null; } private static InputSource search(String systemId, URL containerPath) { URL systemUrl = null; try { systemUrl = new URL(systemId); if (containerPath != null) { systemUrl = FileSystem.makeAbsolute(containerPath, systemUrl); } } catch (Exception e) { // } final InputSource source = getInputSourceFromSystemUrl(systemUrl); if (source != null) { return source; } return getInputSourceFromResources(systemUrl, systemId, containerPath); } @Override public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { if (systemId != null && !"".equals(systemId)) { //$NON-NLS-1$ InputSource is = search(systemId, null); if (is != null) { return is; } if (this.searchPath != null) { is = search(systemId, this.searchPath); if (is != null) { return is; } } } if (this.emptyExternalResource) { return new InputSource(new ByteArrayInputStream(new byte[0])); } return null; } }