I have to validate some xml files with .xsd files, which are listed in catalog.xml, but they are in database. So i need resolver, which will match systemId from catalog.xml with .xsd file stored as blob in database.
I found that XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) method doing this, but I can't find how parser uses this method, so I'm not sure how to override it to do it propertly. I thought that it returns XMLInputStram which contains .xsd file in Stream, but it's not true because of "leaving resolution of the entity and opening of the input stream up to the caller", according to XMLInputSource documentation.
So my question is - how to map entities from catalog.xml with .xsd files stored in database?
I really hope that I explained problem clearly, but I know that my english is really poor - so feel free to ask for more details or better explaation.
Greetings,
Rzysia
Here's the resolver I wrote for the maven-jaxb2-plugin. This resolver resolves system ids to resources in Maven artifacts. This is somewhat similar task to yours.
Your task is, basically, to implement the resolveEntity method.
Normally it is practical to extend an existing CatalogResolver.
Then you can override the getResolvedEntity method.
Typically you first call the super method to resolve systemId/publicId.
Then you try to do you custom resolution.
systemId is normally the resource location URL (or logical URI).
publicId is often the namespace URI.
Here's a simple code snippet from another resolver which resolves classpath:com/acme/foo/schema.xsd in the classpath:
public static final String URI_SCHEME_CLASSPATH = "classpath";
#Override
public String getResolvedEntity(String publicId, String systemId) {
final String result = super.getResolvedEntity(publicId, systemId);
if (result == null) {
return null;
}
try {
final URI uri = new URI(result);
if (URI_SCHEME_CLASSPATH.equals(uri.getScheme())) {
final String schemeSpecificPart = uri.getSchemeSpecificPart();
final URL resource = Thread.currentThread()
.getContextClassLoader()
.getResource(schemeSpecificPart);
if (resource == null) {
return null;
} else {
return resource.toString();
}
} else {
return result;
}
} catch (URISyntaxException urisex) {
return result;
}
}
In your scenario, I'd do the following:
Define the URI schema like database:schema:table:value:id:schema.xsd.
Write a catalog resolver which is capable of resolving such URIs.
Define a catalog file which rewrites namespace URIs or absolute schema location URLs to your database:... URIs.
In simple notation this would be something like:
REWRITE_SYSTEM "http://example.com/schemas" "database:schemas:content:schema_id:example/schemas"
So the "base" catalog resolver would first resolve http://example.com/schemas/schema.xsd into database:schemas:content:schema_id:example/schemas/schema.xsd.
Then your code resolves database:schemas:content:schema_id:example/schemas/schema.xsd into a database resource.
Ok, i found solution - as I thought, method XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) shoud return XMLInputSource with setted my own InputStream containing speciefied xsd schema.
My version of this overrided class:
public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier)
throws XNIException, IOException {
String resolvedId = resolveIdentifier(resourceIdentifier);
if (resolvedId != null) {
XMLInputSource xmlis = new XMLInputSource(resourceIdentifier.getPublicId(),
resolvedId,
resourceIdentifier.getBaseSystemId());
try {
InputStream is = getXSDFromDb(resourceIdentifier.getLiteralSystemId());
xmlis.setByteStream(is);
} catch (SQLException ex) {
ex.printStackTrace();
}
return xmlis;
}
return null;
Related
I am learning about mediaplayer in android.
I wanted some simple and easy to understand code example of MediaPlayer.setDataSource().
Well, for more deep understanding of MediaPlayer that's better to read official documentation https://developer.android.com/reference/android/media/MediaPlayer#setDataSource(android.content.res.AssetFileDescriptor). But for basic comprehension here is the code example.
MediaPlayer mp = new MediaPlayer();
// Here you may set which stream to use either MEDIA or ALARM etc.
mp.setAudioStreamType(AudioManager.STREAM_ALARM);
try {
if (isAnyActiveSongExist){
// Here you may set dataSource as path of the file
mp.setDataSource(firstPrioritySongEntityPath);
}
else{
// Here you may set dataSource using Uri
mp.setDataSource(context, Settings.System.DEFAULT_RINGTONE_URI);
}
mp.prepare();
} catch (IOException e) {
e.printStackTrace();
}
mp.start();
setDataSource() defines which file should be used by your MediaPlayer for playing.
First of all, code never been simple and easy until you'll not go through it. Check this link click here, I think you'll have your answer from here
About setDataSource(String) call
After seeing your comment, it looks like you exactly want setDataSource(string) to be used for your purpose. I don't understand why. But, what I assume is, for some reason you are trying to avoid using "context". If that is not the case then the above two solutions should work perfectly for you or if you are trying to avoid context, I'm afraid that is not possible with the function with signature setDataSource(String) call. The reason is as below,
MediaPlayer setDataSource() function has these below options out of which you are only interested in setDataSource(String),
public void setDataSource(String path)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
setDataSource(path, null, null);
}
and if you check setDataSource(String path, String[] keys, String[] values) code, you will see the below condition filtering the path based on its scheme, particularly if it is "file" scheme it calls setDataSource(FileDescriptor) or if scheme is non "file", it calls native JNI media function.
{
final Uri uri = Uri.parse(path);
final String scheme = uri.getScheme();
if ("file".equals(scheme)) {
path = uri.getPath();
} else if (scheme != null) {
// handle non-file sources
nativeSetDataSource(
MediaHTTPService.createHttpServiceBinderIfNecessary(path),
path,
keys,
values);
return;
}
final File file = new File(path);
if (file.exists()) {
FileInputStream is = new FileInputStream(file);
FileDescriptor fd = is.getFD();
setDataSource(fd);
is.close();
} else {
throw new IOException("setDataSource failed.");
}
}
In the above code, your resource file URI scheme will not be null (android.resource://) and setDataSource(String) will try to use native JNI function nativeSetDataSource() thinking that your path is http/https/rtsp and obviously that call will fail as well without throwing any exception. Thats why your call to setDataSource(String) escapes without an exception and gets to prepare() call with the following exception.
Prepare failed.: status=0x1
So setDataSource(String) override cannot handle your resource file. You need to choose another override for that.
On the other side, check setDataSource(Context context, Uri uri, Map headers) which is used by setDataSource(Context context, Uri uri), it uses AssetFileDescriptor, ContentResolver from your context and openAssetFileDescriptor to open the URI which gets success as openAssetFileDescriptor() can open your resource file and finally the resultant fd is used to call setDataSource(FileDescriptor) override.
AssetFileDescriptor fd = null;
try {
ContentResolver resolver = context.getContentResolver();
fd = resolver.openAssetFileDescriptor(uri, "r");
// :
// :
// :
if (fd.getDeclaredLength() < 0) {
setDataSource(fd.getFileDescriptor());
} else {
setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getDeclaredLength());
}
To conclude, you cannot use setDataSource(String) override as is to use your resource mp3 file. Instead, if you want use string to play your resource file you can use either MediaPlayer.create() static function with getIdentifier() as given above or setDataSource(context,uri) as given in Update#1.
Refer to the complete source code for more understanding here: Android MediaPlayer
I created folder src/test/resources/ in root project directory, and inside this I added a file in folder jsons as jsons/server_request.json.
Now I am trying to read this file by calling a the static function in CommonTestUtilityclass given as:
public class CommonTestUtility {
public static String getFileAsString(String fileName) throws IOException {
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
File file = new File(classLoader.getResource(fileName).getFile());
String content = new String(Files.readAllBytes(file.toPath()));
return content;
}
}
Now while calling this function as
class ServerTest {
#Test
void test_loadResource() {
String content = CommonTestUtility.getFileAsString("jsons/server_request.json");
}
}
, It's giving me the error as:
CommonTestUtility - Cannot invoke "java.net.URL.getFile()" because the return value of "java.lang.ClassLoader.getResource(String)" is null.
I tried to include the src/test/resources/ in the run configuration
of Junit ServerTest.java, but still it's not able to find out the
resource
How to resolve this issue?
https://mkyong.com/java/java-read-a-file-from-resources-folder/
This above link might be helpful.
The getResource() method return an URI you need to change
.getFile() function to. toURI().
Simple code
private File getFileFromResource(String fileName) throws URISyntaxException{
ClassLoader classLoader = getClass().getClassLoader();
URL resource = classLoader.getResource(fileName);
if (resource == null) {
throw new IllegalArgumentException("file not found! " + fileName);
} else {
// failed if files have whitespaces or special characters
//return new File(resource.getFile());
return new File(resource.toURI());
}
}
I recreated the same scenario you describe and your code works for me.
Could you double-check that your project looks like mine below? If so, I suspect it might be something with your environment.
I need to figure out how to validate my XML files with schema's offline. After looking around for a couple of days, what I was able to find was basically that I needed to have an internal reference to the schema. I needed to find them, download them, and change the reference to a local system path. What I was unable to find was exactly how to do that. Where and how can I change the reference to point internally instead of externally? What is the best way to download the schemas?
There are three ways you could do this. What they all have in common is that you need a local copy of the schema document(s). I'm assuming that the instance documents currently use xsi:schemaLocation and/or xsi:noNamespaceSchemaLocation to point to a location holding the schema document(s) on the web.
(a) Modify your instance documents to refer to the local copy of the schema documents. This is usually inconvenient.
(b) Redirect the references so that a request for a remote file is redirected to a local file. The way to set this up depends on which schema validator you are using and how you are invoking it.
(c) Tell the schema processor to ignore the values of xsi:schemaLocation and xsi:noNamespaceSchemaLocation, and to validate instead against a schema that you supply using your schema processor's invocation API. Again the details depend on which schema processor you are using.
My preferred approach is (c): if only because when you are validating a source document, then by definition you don't fully trust it - so why should you trust it to contain a correct xsi:schemaLocation attribute?
XmlValidate is a simple but powerful command-line tool that can perform offline validation of single or multiple XML files against target schemas. It can scan local xml files by file name, directory, or URL.
XmlValidate automatically adds the schemaLocation based on the schema namespace and a config file that mapping to a local file. The tool will validate against whatever XML Schema is referenced in the config file.
Here are example mappings of namespace to target Schema in config file:
http://www.opengis.net/kml/2.2=${XV_HOME}/schemas/kml22.xsd
http://appengine.google.com/ns/1.0=C:/xml/appengine-web.xsd
urn:oasis:names:tc:ciq:xsdschema:xAL:2.0=C:/xml/xAL.xsd
Note that ${XV_HOME} token above is simply an alias for the top-level directory that XmlValidate is running from. The location can likewise be a full file path.
XmlValidate is an open-source project (source code available) that runs with the Java Runtime Environment (JRE). The bundled application (Java jars, examples, etc.) can be downloaded here.
If XmlValidate is run in batch mode against multiple XML files, it will provide a summary of validation results.
Errors: 17 Warnings: 0 Files: 11 Time: 1506 ms
Valid files 8/11 (73%)
You can set your own Implementation of ResourceResolver and LSInput to the SchemaFactory so that the call of
of LSInput.getCharacterStream() will provide a schema from a local path.
I have written an extra class to do offline validation. You can call it like
new XmlSchemaValidator().validate(xmlStream, schemaStream, "https://schema.datacite.org/meta/kernel-4.1/",
"schemas/datacite/kernel-4.1/");
Two InputStream are beeing passed. One for the xml, one for the schema. A baseUrl and a localPath (relative on classpath) are passed as third and fourth parameter. The last two parameters are used by the validator to lookup additional schemas locally at localPath or relative to the provided baseUrl.
I have tested with a set of schemas and examples from https://schema.datacite.org/meta/kernel-4.1/ .
Complete Example:
#Test
public void validate4() throws Exception {
InputStream xmlStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(
"schemas/datacite/kernel-4.1/example/datacite-example-complicated-v4.1.xml");
InputStream schemaStream = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("schemas/datacite/kernel-4.1/metadata.xsd");
new XmlSchemaValidator().validate(xmlStream, schemaStream, "https://schema.datacite.org/meta/kernel-4.1/",
"schemas/datacite/kernel-4.1/");
}
The XmlSchemaValidator will validate the xml against the schema and will search locally for included Schemas. It uses a ResourceResolver to override the standard behaviour and to search locally.
public class XmlSchemaValidator {
/**
* #param xmlStream
* xml data as a stream
* #param schemaStream
* schema as a stream
* #param baseUri
* to search for relative pathes on the web
* #param localPath
* to search for schemas on a local directory
* #throws SAXException
* if validation fails
* #throws IOException
* not further specified
*/
public void validate(InputStream xmlStream, InputStream schemaStream, String baseUri, String localPath)
throws SAXException, IOException {
Source xmlFile = new StreamSource(xmlStream);
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
factory.setResourceResolver((type, namespaceURI, publicId, systemId, baseURI) -> {
LSInput input = new DOMInputImpl();
input.setPublicId(publicId);
input.setSystemId(systemId);
input.setBaseURI(baseUri);
input.setCharacterStream(new InputStreamReader(
getSchemaAsStream(input.getSystemId(), input.getBaseURI(), localPath)));
return input;
});
Schema schema = factory.newSchema(new StreamSource(schemaStream));
javax.xml.validation.Validator validator = schema.newValidator();
validator.validate(xmlFile);
}
private InputStream getSchemaAsStream(String systemId, String baseUri, String localPath) {
InputStream in = getSchemaFromClasspath(systemId, localPath);
// You could just return in; , if you are sure that everything is on
// your machine. Here I call getSchemaFromWeb as last resort.
return in == null ? getSchemaFromWeb(baseUri, systemId) : in;
}
private InputStream getSchemaFromClasspath(String systemId, String localPath) {
System.out.println("Try to get stuff from localdir: " + localPath + systemId);
return Thread.currentThread().getContextClassLoader().getResourceAsStream(localPath + systemId);
}
/*
* You can leave out the webstuff if you are sure that everything is
* available on your machine
*/
private InputStream getSchemaFromWeb(String baseUri, String systemId) {
try {
URI uri = new URI(systemId);
if (uri.isAbsolute()) {
System.out.println("Get stuff from web: " + systemId);
return urlToInputStream(uri.toURL(), "text/xml");
}
System.out.println("Get stuff from web: Host: " + baseUri + " Path: " + systemId);
return getSchemaRelativeToBaseUri(baseUri, systemId);
} catch (Exception e) {
// maybe the systemId is not a valid URI or
// the web has nothing to offer under this address
}
return null;
}
private InputStream urlToInputStream(URL url, String accept) {
HttpURLConnection con = null;
InputStream inputStream = null;
try {
con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(15000);
con.setRequestProperty("User-Agent", "Name of my application.");
con.setReadTimeout(15000);
con.setRequestProperty("Accept", accept);
con.connect();
int responseCode = con.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_MOVED_PERM
|| responseCode == HttpURLConnection.HTTP_MOVED_TEMP || responseCode == 307
|| responseCode == 303) {
String redirectUrl = con.getHeaderField("Location");
try {
URL newUrl = new URL(redirectUrl);
return urlToInputStream(newUrl, accept);
} catch (MalformedURLException e) {
URL newUrl = new URL(url.getProtocol() + "://" + url.getHost() + redirectUrl);
return urlToInputStream(newUrl, accept);
}
}
inputStream = con.getInputStream();
return inputStream;
} catch (SocketTimeoutException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private InputStream getSchemaRelativeToBaseUri(String baseUri, String systemId) {
try {
URL url = new URL(baseUri + systemId);
return urlToInputStream(url, "text/xml");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
prints
Try to get stuff from localdir: schemas/datacite/kernel-4.1/http://www.w3.org/2009/01/xml.xsd
Get stuff from web: http://www.w3.org/2009/01/xml.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-titleType-v4.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-contributorType-v4.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-dateType-v4.1.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-resourceType-v4.1.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-relationType-v4.1.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-relatedIdentifierType-v4.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-funderIdentifierType-v4.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-descriptionType-v4.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-nameType-v4.1.xsd
The print shows that the validator was able to validate against a set of local schemas. Only http://www.w3.org/2009/01/xml.xsd was not available locally and therefore fetched from the internet.
I have a memory class loader (here) that I am using in a custom Minecraft launcher.
Memory Class Loader
Whenever I load up Minecraft (a Java LWJGL game), I am getting the following error:
27 achievements
182 recipes
Setting user
LWJGL Version: 2.4.2
java.lang.IllegalArgumentException: input == null!
at javax.imageio.ImageIO.read(Unknown Source)
at lc.<init>(SourceFile:21)
at gi.<init>(SourceFile:10)
at net.minecraft.client.Minecraft.a(SourceFile:254)
at net.minecraft.client.Minecraft.run(SourceFile:657)
at java.lang.Thread.run(Unknown Source)
I am creating the class loader like this:
Base.cLoader = new CLoader(
GameUpdater.classLoader,
new JarInputStream(new ByteArrayInputStream(jarFileBytes)));
As you can see, it manages to load up the first part then suddenly after LWJGL Version it crashes with "input == null".
Edit - Here is the new getResource method.
The error is on "URL()", as shown.
Code:
public URL getResource(final String name) {
URL url = new URL() { public InputStream openStream() {
return new ByteArrayInputStream((byte[])others.get(name));
}};
return url;
}
A wild guess... it could be this: Warning: URLs for this are not yet implemented! You cannot call getResource() or getResources()!
So your code expects to retrieve an image from the JAR using the unimplemented method. An equivalent of this is probably being executed:
ImageIO.read(memClassLoader.getResource(someString));
Except that, as we have seen, the Error thrown from getResource is getting ignored and null being used as the value. ImageIO.read goes like this:
public static BufferedImage read(URL input) throws IOException {
if (input == null) {
throw new IllegalArgumentException("input == null!");
}
InputStream istream = null;
try {
istream = input.openStream();
} catch (IOException e) {
throw new IIOException("Can't get input stream from URL!", e);
}
}
Sounds familiar? So, this is roughly what you need to implement:
public URL getResource(final String name) {
try {
return new URL("", "", 0, "",
new URLStreamHandler() { public URLConnection openConnection(URL url) {
return new URLConnection(url) {
public void connect() {}
public InputStream getInputStream() {
// return the appropriate InputStream, based on the name arg
}
};
}});
} catch (MalformedURLException e) { throw new RuntimeException(e); }
}
The MemoryClassLoader is pretty much broken. It does not implement getResource() (as stated in the comment in the source), and also it does not define Packages for the classes it loads (this may or may not break an application).
Most likely that ClassLoader was quickly hacked for testing purposes, leaving the more complicated methods out.
Implementing your own URL protocol to handle getResource() is not too difficult, in getResource() you return an URL that uses a custom protocol name (e.g. "myclassloader://resourcename"), and also a custom implementation of URLStreamHandler that handles that protocol.
That may not cover all the loopholes that might cause trouble in locating a resource, if the code loaded through the ClassLoader uses URL.toString() and converts it back it will still break.
Implementing a fully working ClassLoader that does not simple delegation to existing ClassLoaders, is not as simple as most examples make it look.
Xerces claims to allow XML Catalog support to be added to a reader like this:
XMLCatalogResolver resolver = new XMLCatalogResolver();
resolver.setPreferPublic(true);
resolver.setCatalogList(catalogs);
XMLReader reader = XMLReaderFactory.createXMLReader(
"org.apache.xerces.parsers.SAXParser");
reader.setProperty("http://apache.org/xml/properties/internal/entity-resolver",
resolver);
But as soon as I do this then any <xs:include/> tags in my schemas are no longer processed. It seems like the XMLCatalogResolver becomes the only go-to place for entity resolution once it's added, so includes can't work anymore. Eclipse OTOH successfully validates using the same catalog, so it should be possilbe.
Is there a way around this, or are there any other Java based validators that support catalogs?
Thanks, Dominic.
I finally solved this by overriding the XMLCatalogResolver and logging the various calls made to the resolveEntity() method. I observed 3 types of call being made, only one of which made sense to be resolved using the XML catalog. So, I merely returned a FileInputStream directly for the other two call types.
Here is the code I used inside my custom XMLCatalogResolver class:
public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier)
throws IOException
{
if(resourceIdentifier.getExpandedSystemId() != null)
{
return new XMLInputSource(resourceIdentifier.getPublicId(),
resourceIdentifier.getLiteralSystemId(),
resourceIdentifier.getBaseSystemId(),
new FileReader(getFile(resourceIdentifier.getExpandedSystemId())),
"UTF-8");
}
else if((resourceIdentifier.getBaseSystemId() != null) &&
(resourceIdentifier.getNamespace() == null))
{
return new XMLInputSource(resourceIdentifier.getPublicId(),
resourceIdentifier.getLiteralSystemId(),
resourceIdentifier.getBaseSystemId(),
new FileReader(getFile(resourceIdentifier.getBaseSystemId())),
"UTF-8");
}
else
{
return super.resolveEntity(resourceIdentifier);
}
}
private File getFile(String urlString) throws MalformedURLException
{
URL url = new URL(urlString);
return new File(url.toURI());
}
I'm not sure why this wouldn't be done by default within Xerces, but hopefully this helps the next person that encounters this problem.