/******************************************************************************
* Copyright (c) 2016 Oracle
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Konstantin Komissarchik - initial implementation and ongoing maintenance
* Ling Hao - [337232] Certain schema causes elements to be out of order in corresponding xml files
******************************************************************************/
package org.eclipse.sapphire.modeling.xml.schema;
import java.util.List;
import javax.xml.namespace.QName;
/**
* @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
*/
public final class XmlElementDefinitionByReference extends XmlElementDefinition
{
private QName contentModelName = null;
private boolean contentModelResolved = false;
private XmlElementDefinitionByReference( final XmlDocumentSchema schema,
final QName elementName,
final int minOccur,
final int maxOccur )
{
super( schema, elementName, null, minOccur, maxOccur );
}
@Override
public QName getContentModelName()
{
final boolean contentModelResolveNeeded;
synchronized( this )
{
contentModelResolveNeeded = ( ! this.contentModelResolved );
}
if( contentModelResolveNeeded )
{
QName contentModelName = null;
final QName ref = getName();
final String namespace = ref.getNamespaceURI();
final XmlDocumentSchema refSchema;
if( namespace == null || namespace.length() == 0 )
{
refSchema = getSchema();
}
else
{
final String refSchemaLocation = getSchema().getSchemaLocation( namespace );
refSchema = XmlDocumentSchemasCache.getSchema( refSchemaLocation );
}
if( refSchema != null )
{
final XmlElementDefinition refElement = refSchema.getElement( ref.getLocalPart() );
if( refElement != null )
{
contentModelName = refElement.getContentModelName();
}
}
synchronized( this )
{
if( ! this.contentModelResolved )
{
this.contentModelName = contentModelName;
this.contentModelResolved = true;
}
}
}
return this.contentModelName;
}
private XmlElementDefinition getElementInGroup(final QName childElementName) {
final XmlElementDefinition definition = getSchema().getElement(getName().getLocalPart());
// First check to see if this reference is abstract
if (definition != null && definition.isAbstract()) {
// Then see if the childElement specify the substitutionGroup
List<XmlElementDefinition> list = definition.getSubstitutionList();
if (list != null && list.size() > 0) {
for (XmlElementDefinition subGroup : list) {
if (subGroup.getName().equals(childElementName)) {
return subGroup;
}
}
}
}
return null;
}
@Override
public XmlContentModel findChildElementContentModel(QName childElementName) {
final XmlContentModel model = super.findChildElementContentModel(childElementName);
if (model == null) {
XmlElementDefinition subGroup = getElementInGroup(childElementName);
if (subGroup != null) {
return subGroup.getContentModel();
}
}
return model;
}
@Override
protected boolean sameElementName(QName qname) {
boolean isSame = super.sameElementName(qname);
if (!isSame) {
XmlElementDefinition subGroup = getElementInGroup(qname);
if (subGroup != null) {
return true;
}
}
return isSame;
}
public static final class Factory extends XmlElementDefinition.Factory
{
@Override
public QName getContentModelName()
{
throw new UnsupportedOperationException();
}
@Override
public void setContentModelName( final QName contentModelName )
{
throw new UnsupportedOperationException();
}
@Override
public void setContentModelName( final String contentModelName )
{
throw new UnsupportedOperationException();
}
@Override
public XmlContentModel create( final XmlDocumentSchema schema )
{
return new XmlElementDefinitionByReference( schema, this.elementName, this.minOccur, this.maxOccur );
}
}
}