/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.avro.xml; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; import javax.xml.namespace.QName; import javax.xml.transform.stream.StreamSource; /** * Configuration for setting up the {@link XmlDatumWriter}. XML Schemas may * be defined by {@link java.net.URL}s and/or {@link java.io.File}s, and the * name of the XML Document's root tag {@link javax.xml.namespace.QName} is * needed to determine how to parse the XML Schema or Schemas. * * <p> * When using files, a Schema URI is required. If the Schema contains * references to incomplete paths, this URI will be used to track them * down. * </p> */ public class XmlDatumConfig { private ArrayList<URL> schemaUrls; private ArrayList<File> schemaFiles; private String baseUri; private QName baseTagName; private XmlDatumConfig(QName rootTagName) { baseTagName = rootTagName; schemaUrls = null; schemaFiles = null; baseUri = null; } /** * Creates a new <code>XmlDatumConfig</code> from the {@link java.net.URL} * to fetch the XML Schema from and the {@link QName} representing the * root element. * * @param schema The URL of the XML Schema to read. * @param rootTagName The <code>QName</code> of the root element. */ public XmlDatumConfig(URL schema, QName rootTagName) { this(rootTagName); schemaUrls = new ArrayList<URL>(1); schemaUrls.add(schema); baseUri = getBaseUriFor(schema); } /** * Creates a new <code>XmlDatumConfig</code> from a local {@link File} * to read the XML Schema from and the {@link QName} representing the * root element. A base URI is also required as the default path to * fetch any referenced schemas from. * * @param schema The path to the XML Schema to read. * * @param schemaBaseUri The base URI of the schema - a default URI of * where to retrieve other referenced schemas. * * @param rootTagName The <code>QName</code> of the root element. */ public XmlDatumConfig(File schema, String schemaBaseUri, QName rootTagName) { this(rootTagName); schemaFiles = new ArrayList<File>(1); schemaFiles.add(schema); baseUri = schemaBaseUri; } /** * <p> * The base URI. If this <code>XmlDatumConfig</code> was created with a * URL, the base URI is the URL up to, but not including the schema file * name. * </p> * <p> * If the <code>XmlDatumConfig</code> was created with a <code>File</code>, * this is the <code>schemaBaseUri</code> provided in that constructor. * </p> */ public String getBaseUri() { return baseUri; } /** * The list of XML Schema URLs provided via * {@link #XmlDatumConfig(URL, QName)} and * any subsequent calls to * {@link #addSchemaUrl(URL)}. */ public List<URL> getSchemaUrls() { return schemaUrls; } /** * The list of XML Schema files provided via * {@link #XmlDatumConfig(File, String, QName)} * and any subsequent calls to * {@link #addSchemaFile(File)}. */ public List<File> getSchemaFiles() { return schemaFiles; } /** * The XML Schema's root tag passed into the constructor. */ public QName getRootTagName() { return baseTagName; } /** * Adds a URL to an XML Schema to include when generating Avro. */ public void addSchemaUrl(URL schemaUrl) { if (schemaUrls == null) { schemaUrls = new ArrayList<URL>(1); } schemaUrls.add(schemaUrl); } /** * Adds a file path to an XML Schema to include when generating Avro. */ public void addSchemaFile(File file) { if (schemaFiles == null) { schemaFiles = new ArrayList<File>(1); } schemaFiles.add(file); } @SuppressWarnings("resource") List<StreamSource> getSources() throws IOException { final ArrayList<StreamSource> sources = new ArrayList<StreamSource>( getArraySize() ); try { if (schemaUrls != null) { for (URL schemaUrl : schemaUrls) { final StreamSource source = new StreamSource( schemaUrl.openStream(), schemaUrl.toString()); sources.add(source); } } if (schemaFiles != null) { for (File schemaFile : schemaFiles) { final StreamSource source = new StreamSource( new FileReader(schemaFile), schemaFile.getName()); sources.add(source); } } } catch (IOException ioe) { for (StreamSource source : sources) { try { if (source.getInputStream() != null) { source.getInputStream().close(); } else { source.getReader().close(); } } catch (IOException failedClose) { failedClose.printStackTrace(); } } throw ioe; } return sources; } private int getArraySize() { int count = 0; if (schemaUrls != null) { count += schemaUrls.size(); } if (schemaFiles != null) { count += schemaFiles.size(); } return count; } private static String getBaseUriFor(URL url) { StringBuilder namespace = new StringBuilder( url.getProtocol() ); namespace.append("://").append( url.getHost() ); if (url.getPort() != -1) { namespace.append(':').append( url.getPort() ); } namespace.append( url.getPath() ); String namespaceWithFile = namespace.toString(); int lastSlashBeforeFileIndex = namespaceWithFile.lastIndexOf('/'); return namespaceWithFile.substring(0, lastSlashBeforeFileIndex + 1); } }