All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opencypher.tools.xml.AttributeHandler Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2015-2018 "Neo Technology,"
 * Network Engine for Objects in Lund AB [http://neotechnology.com]
 *
 * Licensed 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.
 *
 * Attribution Notice under the terms of the Apache License 2.0
 *
 * This work was created by the collective efforts of the openCypher community.
 * Without limiting the terms of Section 6, any Derivative Work that is not
 * approved by the public consensus process of the openCypher Implementers Group
 * should not be described as “Cypher” (and Cypher® is a registered trademark of
 * Neo4j Inc.) or as "openCypher". Extensions by implementers or prototypes or
 * proposals for change that have been documented or implemented should only be
 * described as "implementation extensions to Cypher" or as "proposed changes to
 * Cypher that are not yet approved by the openCypher community".
 */
package org.opencypher.tools.xml;

import java.lang.invoke.MethodHandle;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

import static java.lang.invoke.MethodHandles.dropArguments;
import static java.lang.invoke.MethodHandles.explicitCastArguments;
import static java.lang.invoke.MethodHandles.filterArguments;
import static java.lang.invoke.MethodType.methodType;

final class AttributeHandler
{
    final String uri, name;
    final boolean optional;
    private final MethodHandle setter;

    AttributeHandler( String uri, String name, boolean optional, MethodHandle setter )
    {
        this.uri = uri;
        this.name = name;
        this.optional = optional;
        this.setter = setter;
    }

    @Override
    public String toString()
    {
        return String.format( "%sAttribute{uri='%s', name='%s'}", optional ? "Optional" : "", uri, name );
    }

    public boolean matches( String uri, String name )
    {
        return this.uri.equalsIgnoreCase( uri ) && this.name.equalsIgnoreCase( name );
    }

    public void apply( Object target, Resolver resolver, String value )
    {
        try
        {
            setter.invokeWithArguments( target, resolver, value );
        }
        catch ( RuntimeException | Error e )
        {
            throw e;
        }
        catch ( Throwable throwable )
        {
            throw new RuntimeException( throwable );
        }
    }

    private static final Map, Function> CONVERSION = new ConcurrentHashMap<>();
    private static final MethodHandle ENUM_VALUE_OF = Reference.biFunction( Enum::valueOf ).mh();
    private static final MethodHandle UPPER_STRING = Reference.function( String::toUpperCase ).mh();

    public static MethodHandle conversion( Class type, MethodHandle setter )
    {
        return CONVERSION.computeIfAbsent( type, AttributeHandler::conversion ).apply( setter );
    }

    static
    {
        CONVERSION.put( String.class, ( mh ) -> dropArguments( mh, 1, Resolver.class ) );
        CONVERSION.put( int.class, conversion( Reference.toInt( Integer::parseInt ) ) );
        CONVERSION.put( Integer.class, conversion( Reference.function( Integer::valueOf ) ) );
        CONVERSION.put( boolean.class, conversion( Reference.toBool( Boolean::parseBoolean ) ) );
        CONVERSION.put( Boolean.class, conversion( Reference.function( Boolean::valueOf ) ) );
        CONVERSION.put( long.class, conversion( Reference.toLong( Long::parseLong ) ) );
        CONVERSION.put( Long.class, conversion( Reference.function( Long::valueOf ) ) );
        CONVERSION.put( double.class, conversion( Reference.toDouble( Double::parseDouble ) ) );
        CONVERSION.put( Double.class, conversion( Reference.function( Double::valueOf ) ) );
        Resolver.initialize( CONVERSION::put );
    }

    private static Function conversion( Reference reference )
    {
        MethodHandle filter = reference.mh();
        return conversion( filter );
    }

    private static Function conversion( Class type )
    {
        if ( type.isEnum() )
        {
            return enumConversion( type );
        }
        throw new IllegalArgumentException( "Unsupported field type: " + type );
    }

    private static Function enumConversion( Class enumType )
    {
        return conversion( explicitCastArguments(
                filterArguments( ENUM_VALUE_OF.bindTo( enumType ), 0, UPPER_STRING ),
                methodType( enumType, String.class ) ) );
    }

    private static Function conversion( MethodHandle filter )
    {
        return mh -> dropArguments( filterArguments( mh, 1, filter ), 1, Resolver.class );
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy