Package org.eclipse.sapphire.modeling.xml

Source Code of org.eclipse.sapphire.modeling.xml.StandardXmlElementBindingImpl

/******************************************************************************
* Copyright (c) 2014 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 - [376531] Need ability to distinguish between switch among heterogeneous elements
******************************************************************************/

package org.eclipse.sapphire.modeling.xml;

import static org.eclipse.sapphire.modeling.util.MiscUtil.indexOf;
import static org.eclipse.sapphire.modeling.xml.XmlUtil.contains;
import static org.eclipse.sapphire.modeling.xml.XmlUtil.createQualifiedName;
import static org.eclipse.sapphire.modeling.xml.XmlUtil.equal;

import java.util.SortedSet;

import javax.xml.namespace.QName;

import org.eclipse.sapphire.Element;
import org.eclipse.sapphire.ElementType;
import org.eclipse.sapphire.Event;
import org.eclipse.sapphire.Listener;
import org.eclipse.sapphire.LocalizableText;
import org.eclipse.sapphire.Property;
import org.eclipse.sapphire.PropertyDef;
import org.eclipse.sapphire.Resource;
import org.eclipse.sapphire.Text;
import org.eclipse.sapphire.modeling.LayeredElementBindingImpl;
import org.eclipse.sapphire.modeling.xml.annotations.XmlBinding;
import org.eclipse.sapphire.modeling.xml.annotations.XmlElementBinding;
import org.eclipse.sapphire.services.PossibleTypesService;

/**
* @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
*/

public class StandardXmlElementBindingImpl extends LayeredElementBindingImpl
{
    @Text( "{0}.{1} : {2}" )
    private static LocalizableText failure;
   
    @Text( "Element name must be specified in @XmlElementBinding.Mapping annotation." )
    private static LocalizableText mustSpecifyElementNameMsg;
   
    static
    {
        LocalizableText.init( StandardXmlElementBindingImpl.class );
    }

    private PossibleTypesService possibleTypesService;
    private Listener possibleTypesServiceListener;
    private XmlPath path;
    private QName[] xmlElementNames;
    private ElementType[] modelElementTypes;
   
    @Override
    public void init( final Property property )
    {
        super.init( property );
       
        this.possibleTypesService = property.service( PossibleTypesService.class );
       
        this.possibleTypesServiceListener = new Listener()
        {
            @Override
            public void handle( final Event event )
            {
                initBindingMetadata();
            }
        };
       
        this.possibleTypesService.attach( this.possibleTypesServiceListener );
       
        initBindingMetadata();
    }
   
    private void initBindingMetadata()
    {
        final Element element = property().element();
        final PropertyDef property = property().definition();
       
        try
        {
            final XmlElementBinding xmlElementBindingAnnotation = property.getAnnotation( XmlElementBinding.class );
            final XmlNamespaceResolver xmlNamespaceResolver = ( (XmlResource) element.resource() ).getXmlNamespaceResolver();
           
            final SortedSet<ElementType> possible = this.possibleTypesService.types();
            this.modelElementTypes = possible.toArray( new ElementType[ possible.size() ] );

            if( xmlElementBindingAnnotation == null )
            {
                final XmlBinding xmlBindingAnnotation = property.getAnnotation( XmlBinding.class );
               
                if( xmlBindingAnnotation != null && possible.size() == 1 )
                {
                    final String path = xmlBindingAnnotation.path();
                    final int slashIndex = path.lastIndexOf( '/' );
                   
                    if( slashIndex == -1 )
                    {
                        this.xmlElementNames = new QName[] { createQualifiedName( path, xmlNamespaceResolver ) };
                    }
                    else if( slashIndex > 0 && slashIndex < path.length() - 1 )
                    {
                        this.path = new XmlPath( path.substring( 0, slashIndex ), xmlNamespaceResolver );
                        this.xmlElementNames = new QName[] { createQualifiedName( path.substring( slashIndex + 1 ), xmlNamespaceResolver ) };
                    }
                }
               
                if( this.xmlElementNames == null )
                {
                    this.path = new XmlPath( property.name(), ( (XmlResource) element.resource() ).getXmlNamespaceResolver() );
                   
                    this.xmlElementNames = new QName[ this.modelElementTypes.length ];
                   
                    for( int i = 0; i < this.modelElementTypes.length; i++ )
                    {
                        this.xmlElementNames[ i ] = createDefaultElementName( this.modelElementTypes[ i ], xmlNamespaceResolver );
                    }
                }
            }
            else
            {
                if( xmlElementBindingAnnotation.path().length() > 0 )
                {
                    this.path = new XmlPath( xmlElementBindingAnnotation.path(), xmlNamespaceResolver );
                }
               
                final XmlElementBinding.Mapping[] mappings = xmlElementBindingAnnotation.mappings();
                this.xmlElementNames = new QName[ this.modelElementTypes.length ];
               
                for( int i = 0; i < this.modelElementTypes.length; i++ )
                {
                    final ElementType type = this.modelElementTypes[ i ];
                           
                    for( XmlElementBinding.Mapping mapping : mappings )
                    {
                        if( mapping.type() == type.getModelElementClass() )
                        {
                            final String mappingElementName = mapping.element().trim();
                           
                            if( mappingElementName.length() == 0 )
                            {
                                throw new RuntimeException( mustSpecifyElementNameMsg.text() );
                            }

                            this.xmlElementNames[ i ] = createQualifiedName( mappingElementName, xmlNamespaceResolver );
                           
                            break;
                        }
                    }
                   
                    if( this.xmlElementNames[ i ] == null )
                    {
                        this.xmlElementNames[ i ] = createDefaultElementName( type, xmlNamespaceResolver );
                    }
                }
            }
        }
        catch( Exception e )
        {
            final String msg = failure.format( element.type().getSimpleName(), property.name(), e.getMessage() );
            throw new RuntimeException( msg, e );
        }
    }
   
    /**
     * Creates the XML element name for a type that does not have an explicit mapping. This method can be
     * overridden to provide custom behavior.
     *
     * @param type the model element type
     * @param xmlNamespaceResolver the resolver of XML namespace suffixes to declared namespaces
     * @return the qualified XML element name for the given model element type
     */
   
    protected QName createDefaultElementName( final ElementType type,
                                              final XmlNamespaceResolver xmlNamespaceResolver )
    {
        return XmlUtil.createDefaultElementName( type );
    }
   
    @Override
    public ElementType type( final Resource resource )
    {
        final XmlElement xmlElement = ( (XmlResource) resource ).getXmlElement();
        final QName xmlElementName = createQualifiedName( xmlElement.getDomNode() );
        final String xmlElementNamespace = xmlElementName.getNamespaceURI();
       
        for( int i = 0; i < this.xmlElementNames.length; i++ )
        {
            if( equal( this.xmlElementNames[ i ], xmlElementName, xmlElementNamespace ) )
            {
                return this.modelElementTypes[ i ];
            }
        }
       
        throw new IllegalStateException();
    }

    @Override
    protected Object readUnderlyingObject()
    {
        final XmlElement parent = parent( false );
       
        if( parent != null )
        {
            for( XmlElement element : parent.getChildElements() )
            {
                final QName xmlElementName = createQualifiedName( element.getDomNode() );
               
                if( contains( this.xmlElementNames, xmlElementName, xmlElementName.getNamespaceURI() ) )
                {
                    return element;
                }
            }
        }
       
        return null;
    }

    @Override
    protected Object createUnderlyingObject( final ElementType type )
    {
        final XmlElement base = base( false );
        if( base != null )
        {
            final XmlElement parent = parent( false );
           
            if( parent != null )
            {
                for( XmlElement element : parent.getChildElements() )
                {
                    final QName xmlElementName = createQualifiedName( element.getDomNode() );
                   
                    if( contains( this.xmlElementNames, xmlElementName, xmlElementName.getNamespaceURI() ) )
                    {
                        element.remove();
                    }
                }
            }
        }
     
        final XmlElement parent = parent( true );
        QName xmlElementName = this.xmlElementNames[ indexOf( this.modelElementTypes, type ) ];
       
        if( xmlElementName.getNamespaceURI().equals( "" ) )
        {
            xmlElementName = new QName( parent.getNamespace(), xmlElementName.getLocalPart() );
        }
       
        return parent.getChildElement( xmlElementName, true );
    }

    @Override
    protected Resource createResource( final Object obj )
    {
        final XmlElement xmlElement = (XmlElement) obj;
        final XmlResource parentXmlResource = (XmlResource) property().element().resource();
       
        return new ChildXmlResource( parentXmlResource, xmlElement );
    }
   
    @Override
    public void remove()
    {
        final XmlElement base = base( false );
       
        if( base != null )
        {
            final XmlElement parent = parent( false );
           
            if( parent != null )
            {
                for( XmlElement element : parent.getChildElements() )
                {
                    final QName xmlElementName = createQualifiedName( element.getDomNode() );
                   
                    if( contains( this.xmlElementNames, xmlElementName, xmlElementName.getNamespaceURI() ) )
                    {
                        element.remove();
                    }
                }
               
                if( parent != base && parent.isEmpty() )
                {
                    base.removeChildNode( this.path );
                }
            }
        }
    }

    protected XmlElement parent( final boolean createIfNecessary )
    {
        XmlElement parent = base( createIfNecessary );
       
        if( parent != null && this.path != null )
        {
            parent = (XmlElement) parent.getChildNode( this.path, createIfNecessary );
        }
       
        return parent;
    }
   
    protected XmlElement base( final boolean createIfNecessary )
    {
        final XmlResource resource = (XmlResource) property().element().resource();
        return resource.getXmlElement( createIfNecessary );
    }

    @Override
    public void dispose()
    {
        super.dispose();
       
        if( this.possibleTypesService != null )
        {
            this.possibleTypesService.detach( this.possibleTypesServiceListener );
        }
    }
   
}
TOP

Related Classes of org.eclipse.sapphire.modeling.xml.StandardXmlElementBindingImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.