Package org.apache.deltaspike.jsf.impl.config.view

Source Code of org.apache.deltaspike.jsf.impl.config.view.DefaultConfigNodeConverter

/*
* 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.deltaspike.jsf.impl.config.view;

import org.apache.deltaspike.core.api.config.ConfigResolver;
import org.apache.deltaspike.core.api.config.view.metadata.Aggregated;
import org.apache.deltaspike.core.api.config.view.ViewConfig;
import org.apache.deltaspike.core.api.config.view.metadata.SkipMetaDataMerge;
import org.apache.deltaspike.core.api.config.view.metadata.ViewMetaData;
import org.apache.deltaspike.core.api.config.view.metadata.ConfigDescriptor;
import org.apache.deltaspike.core.spi.config.view.ConfigNodeConverter;
import org.apache.deltaspike.core.spi.config.view.ConfigPreProcessor;
import org.apache.deltaspike.core.spi.config.view.ViewConfigNode;
import org.apache.deltaspike.core.util.ClassUtils;
import org.apache.deltaspike.core.util.ExceptionUtils;
import org.apache.deltaspike.core.util.metadata.AnnotationInstanceProvider;
import org.apache.deltaspike.jsf.api.config.view.Folder;
import org.apache.deltaspike.jsf.api.config.view.View;
import org.apache.deltaspike.jsf.impl.util.ViewConfigUtils;

import javax.enterprise.inject.Stereotype;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class DefaultConfigNodeConverter implements ConfigNodeConverter
{
    @Override
    public ConfigDescriptor convert(ViewConfigNode node)
    {
        List<Annotation> mergedMetaData = mergeMetaData(node.getMetaData(), node.getInheritedMetaData());
        //e.g. replace default placeholders needed for the merge with real default values
        mergedMetaData = preProcessMetaData(mergedMetaData, node);

        Class sourceClass = node.getSource();

        if (ViewConfigUtils.isFolderConfig(sourceClass))
        {
            Folder folderAnnotation = findMetaDataByType(mergedMetaData, Folder.class);
            return new DefaultFolderConfigDescriptor(folderAnnotation.name(), node.getSource(),
                    mergedMetaData, node.getCallbackDescriptors());
        }
        else if (ViewConfig.class.isAssignableFrom(sourceClass))
        {
            View viewAnnotation = findMetaDataByType(mergedMetaData, View.class);
            String viewId = viewAnnotation.basePath() + viewAnnotation.name() + "." + viewAnnotation.extension();
            return new DefaultViewPathConfigDescriptor(viewId, node.getSource(),
                    filterInheritedFolderMetaData(mergedMetaData), node.getCallbackDescriptors());
        }
        else
        {
            throw new IllegalStateException(node.getSource() + " isn't a valid view-config");
        }
    }

    private <T> T findMetaDataByType(List<Annotation> metaData, Class<T> target)
    {
        for (Annotation annotation : metaData)
        {
            if (target.equals(annotation.annotationType()))
            {
                return (T) annotation;
            }
        }

        return null;
    }

    private List<Annotation> mergeMetaData(Set<Annotation> metaData, List<Annotation> inheritedMetaData)
    {
        //TODO add qualifier support
        List<Annotation> nodeViewMetaData = new ArrayList<Annotation>();
        List<Annotation> viewMetaDataFromStereotype = new ArrayList<Annotation>();

        for (Annotation annotation : metaData)
        {
            if (annotation.annotationType().isAnnotationPresent(ViewMetaData.class))
            {
                nodeViewMetaData.add(annotation);
            }

            //TODO move to stereotype-util, improve it and merge it with DefaultViewConfigInheritanceStrategy
            if (annotation.annotationType().isAnnotationPresent(Stereotype.class))
            {
                for (Annotation metaAnnotation : annotation.annotationType().getAnnotations())
                {
                    if (metaAnnotation.annotationType().isAnnotationPresent(ViewMetaData.class))
                    {
                        viewMetaDataFromStereotype.add(metaAnnotation);
                    }
                }
            }
        }

        //merge meta-data of same level
        List<Annotation> result = mergeAnnotationInstances(viewMetaDataFromStereotype, nodeViewMetaData);

        if (inheritedMetaData != null && !inheritedMetaData.isEmpty())
        {
            //merge meta-data with levels above
            result = mergeAnnotationInstances(inheritedMetaData, result);
        }

        return result;
    }

    private List<Annotation> mergeAnnotationInstances(List<Annotation> inheritedMetaData, List<Annotation> nodeMetaData)
    {
        List<Annotation> mergedResult = new ArrayList<Annotation>();

        for (Annotation inheritedAnnotation : inheritedMetaData)
        {
            ViewMetaData viewMetaData = inheritedAnnotation.annotationType().getAnnotation(ViewMetaData.class);

            if (viewMetaData == null)
            {
                continue;
            }

            Aggregated aggregated = inheritedAnnotation.annotationType().getAnnotation(Aggregated.class);

            if (aggregated == null)
            {
                aggregated = viewMetaData.annotationType().getAnnotation(Aggregated.class);
            }

            if (aggregated.value()) //aggregation for the whole annotation is allowed
            {
                mergedResult.add(inheritedAnnotation);
            }
            else
            {
                Annotation currentNodeMetaData = findInResult(nodeMetaData, inheritedAnnotation);
                if (currentNodeMetaData == null)
                {
                    Annotation mergedMetaData = findInResult(mergedResult, inheritedAnnotation);

                    if (mergedMetaData == null)
                    {
                        mergedResult.add(inheritedAnnotation);
                    }
                    else
                    {
                        Annotation mergedAnnotation = mergeAnnotationInstance(mergedMetaData, inheritedAnnotation);
                        mergedResult.add(mergedAnnotation);
                    }
                }
                else
                {
                    Annotation mergedAnnotation = mergeAnnotationInstance(currentNodeMetaData, inheritedAnnotation);
                    mergedResult.add(mergedAnnotation);
                }
            }
        }

        //add all annotations at the beginning which weren't used for the merge
        mergedResult.addAll(0, nodeMetaData);
        return mergedResult;
    }

    private Annotation mergeAnnotationInstance(Annotation existingMetaData, Annotation inheritedMetaData)
    {
        Map<String, Object> values = new HashMap<String, Object>();

        for (Method annotationMethod : existingMetaData.annotationType().getDeclaredMethods())
        {
            annotationMethod.setAccessible(true); //TODO

            Annotation defaultAnnotation = AnnotationInstanceProvider.of(existingMetaData.annotationType());
            try
            {
                Object defaultValue = annotationMethod.invoke(defaultAnnotation);
                Object existingValue = annotationMethod.invoke(existingMetaData);

                if (existingValue == null /*possible with literal instances*/ ||
                        existingValue.equals(defaultValue))
                {
                    Object inheritedValue = annotationMethod.invoke(inheritedMetaData);

                    if (inheritedValue == null /*possible with literal instances*/ ||
                            inheritedValue.equals(defaultValue) ||
                            annotationMethod.isAnnotationPresent(SkipMetaDataMerge.class))
                    {
                        values.put(annotationMethod.getName(), defaultValue);
                    }
                    else
                    {
                        values.put(annotationMethod.getName(), inheritedValue);
                    }
                }
                else
                {
                    values.put(annotationMethod.getName(), existingValue);
                }
            }
            catch (Exception e)
            {
                ExceptionUtils.throwAsRuntimeException(e);
            }
        }
        //TODO add aggregation in case of arrays
        return AnnotationInstanceProvider.of(existingMetaData.annotationType(), values);
    }

    private List<Annotation> preProcessMetaData(List<Annotation> mergedMetaData, ViewConfigNode node)
    {
        List<Annotation> result = new ArrayList<Annotation>(mergedMetaData.size());

        for (Annotation annotation : mergedMetaData)
        {
            ViewMetaData viewMetaData = annotation.annotationType().getAnnotation(ViewMetaData.class);
            Class<? extends ConfigPreProcessor> preProcessorClass = viewMetaData.preProcessor();
            if (!ConfigPreProcessor.class.equals(preProcessorClass))
            {
                String customPreProcessorClassName = ConfigResolver.getPropertyValue(preProcessorClass.getName(), null);

                if (customPreProcessorClassName != null)
                {
                    Class<? extends ConfigPreProcessor> customPreProcessorClass =
                            ClassUtils.tryToLoadClassForName(customPreProcessorClassName, ConfigPreProcessor.class);

                    if (customPreProcessorClass != null)
                    {
                        preProcessorClass = customPreProcessorClass;
                    }
                    else
                    {
                        throw new IllegalStateException(customPreProcessorClassName + " is configured to replace " +
                            preProcessorClass.getName() + ", but it wasn't possible to load it.");
                    }
                }
                ConfigPreProcessor preProcessor = ClassUtils.tryToInstantiateClass(preProcessorClass);
                result.add(preProcessor.beforeAddToConfig(annotation, node));
            }
            else
            {
                result.add(annotation);
            }
        }

        return result;
    }

    private Annotation findInResult(List<Annotation> annotationList, Annotation annotationToFind)
    {
        for (Annotation annotation : annotationList)
        {
            if (annotationToFind.annotationType().equals(annotation.annotationType()))
            {
                annotationList.remove(annotation);
                return annotation;
            }
        }
        return null;
    }

    private List<Annotation> filterInheritedFolderMetaData(List<Annotation> mergedMetaData)
    {
        List<Annotation> result = new ArrayList<Annotation>();

        for (Annotation metaData : mergedMetaData)
        {
            if (!Folder.class.equals(metaData.annotationType()))
            {
                result.add(metaData);
            }
        }

        return result;
    }
}
TOP

Related Classes of org.apache.deltaspike.jsf.impl.config.view.DefaultConfigNodeConverter

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.