org.codehaus.mojo.jaxb2.helpers.SimpleNamespaceResolver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaxb2-maven-plugin Show documentation
Show all versions of jaxb2-maven-plugin Show documentation
Mojo's JAXB-2 Maven plugin is used to create an object graph
from XSDs based on the JAXB 2.x implementation and to generate XSDs
from JAXB annotated Java classes.
package org.codehaus.mojo.jaxb2.helpers;
/*
* 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.
*/
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import org.codehaus.plexus.util.IOUtil;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* Namespace resolver for XML documents. Doubles as a JAXB NamespaeContext, if we decide to
* use JAXB instead of DOM to parse our generated schema files.
*
* @author Lennart Jörelid
*/
public class SimpleNamespaceResolver
implements NamespaceContext
{
// Constants
private static final String DEFAULT_NS = "DEFAULT";
private static final String TARGET_NAMESPACE = "targetNamespace";
private static final String SCHEMA = "schema";
// Internal state
private String sourceFilename;
private String localNamespaceURI;
private Map prefix2Uri = new HashMap();
private Map uri2Prefix = new HashMap();
/**
* Creates a new SimpleNamespaceResolver which collects namespace data
* from the provided XML file.
*
* @param xmlFile The XML file from which to collect namespace data, should not be null.
*/
public SimpleNamespaceResolver( final File xmlFile )
{
this.sourceFilename = xmlFile.getName();
Reader reader = null;
try
{
reader = new FileReader( xmlFile );
initialize( reader );
}
catch ( FileNotFoundException e )
{
throw new IllegalArgumentException( "File [" + xmlFile + "] could not be found." );
}
finally
{
IOUtil.close( reader );
}
}
/** {@inheritDoc} */
public String getNamespaceURI( final String prefix )
{
if ( prefix == null )
{
// Be compliant with the JAXB contract for NamespaceResolver.
throw new IllegalArgumentException( "Cannot handle null prefix argument." );
}
return prefix2Uri.get( XMLConstants.DEFAULT_NS_PREFIX.equals( prefix ) ? DEFAULT_NS : prefix );
}
/** {@inheritDoc} */
public String getPrefix( final String namespaceURI )
{
if ( namespaceURI == null )
{
// Be compliant with the JAXB contract for NamespaceResolver.
throw new IllegalArgumentException( "Cannot acquire prefix for null namespaceURI." );
}
return uri2Prefix.get( namespaceURI );
}
/** {@inheritDoc} */
public Iterator getPrefixes( String namespaceURI )
{
if ( namespaceURI == null )
{
// Be compliant with the JAXB contract for NamespaceResolver.
throw new IllegalArgumentException( "Cannot acquire prefixes for null namespaceURI." );
}
return Collections.singletonList( uri2Prefix.get( namespaceURI ) ).iterator();
}
/**
* @return A readonly map relating namespace URIs to namespace prefixes.
*/
public Map getNamespaceURI2PrefixMap()
{
return Collections.unmodifiableMap( uri2Prefix );
}
/**
* @return The namespace URI of the default namespace within the sourceFile of this SimpleNamespaceResolver.
*/
public String getLocalNamespaceURI()
{
return localNamespaceURI;
}
/**
* @return The name of the source file used for this SimpleNamespaceResolver.
*/
public String getSourceFilename()
{
return sourceFilename;
}
//
// Private helpers
//
/**
* Initializes this SimpleNamespaceResolver to collect namespace data from the provided stream.
*
* @param xmlFileStream A Reader connected to the XML file from which we should read namespace data.
*/
private void initialize( final Reader xmlFileStream )
{
// Build a DOM model.
final Document parsedDocument = SchemagenHelper.parseXmlStream( xmlFileStream );
// Process the DOM model.
SchemagenHelper.process( parsedDocument.getFirstChild(), true, new NamespaceAttributeNodeProcessor() );
}
class NamespaceAttributeNodeProcessor
implements NodeProcessor
{
/**
* Defines if this visitor should process the provided node.
*
* @param aNode The DOM node to process.
* @return true
if the provided Node should be processed by this NodeProcessor.
*/
public boolean accept( Node aNode )
{
if ( aNode.getNamespaceURI() != null && XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(
aNode.getNamespaceURI() ) )
{
return true;
}
// Is this Node the targetNamespace attribute?
if ( aNode instanceof Attr )
{
final Attr attribute = (Attr) aNode;
final Element parent = attribute.getOwnerElement();
if ( XMLConstants.W3C_XML_SCHEMA_NS_URI.equals( parent.getNamespaceURI() )
&& SCHEMA.equalsIgnoreCase( parent.getLocalName() )
&& TARGET_NAMESPACE.equals( attribute.getLocalName() ) )
{
SimpleNamespaceResolver.this.localNamespaceURI = attribute.getNodeValue();
}
}
// Ignore processing this Node.
return false;
}
/**
* Processes the provided DOM Node.
*
* @param aNode The DOM Node to process.
*/
public void process( Node aNode )
{
// If we have no namespace, use the DEFAULT_NS as the prefix
final String cacheKey =
( XMLConstants.XMLNS_ATTRIBUTE.equals( aNode.getNodeName() ) ) ? DEFAULT_NS : aNode.getLocalName();
final String nodeValue = aNode.getNodeValue();
// Cache the namespace in both caches.
final String oldUriValue = prefix2Uri.put( cacheKey, nodeValue );
final String oldPrefixValue = uri2Prefix.put( nodeValue, cacheKey );
// Check sanity; we should not be overwriting values here.
if ( oldUriValue != null )
{
throw new IllegalStateException(
"Replaced URI [" + oldUriValue + "] with [" + aNode.getNodeValue() + "] for prefix [" + cacheKey
+ "]" );
}
if ( oldPrefixValue != null )
{
throw new IllegalStateException(
"Replaced prefix [" + oldPrefixValue + "] with [" + cacheKey + "] for URI [" + aNode.getNodeValue()
+ "]" );
}
}
}
}