com.github.hateoas.forms.spring.uber.UberUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.github.hateoas.forms.spring.uber.UberUtils.java

Source

/*
 * Copyright (c) 2015. Escalon System-Entwicklung, Dietrich Schulten
 *
 * 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.
 */

package com.github.hateoas.forms.spring.uber;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.*;
import java.util.Map.Entry;

import org.springframework.hateoas.Link;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMethod;

import com.github.hateoas.forms.affordance.*;
import com.github.hateoas.forms.spring.SpringActionDescriptor;

public class UberUtils {

    private UberUtils() {

    }

    static final Set<String> FILTER_RESOURCE_SUPPORT = new HashSet<String>(Arrays.asList("class", "links", "id"));
    static final Set<String> FILTER_BEAN = new HashSet<String>(Arrays.asList("class"));

    /**
     * Recursively converts object to nodes of uber data.
     *
     * @param objectNode to append to
     * @param object to convert
     */
    public static void toUberData(AbstractUberNode objectNode, Object object) {
        Set<String> filtered = FILTER_RESOURCE_SUPPORT;
        if (object == null) {
            return;
        }
        try {
            // TODO: move all returns to else branch of property descriptor handling
            if (object instanceof Resource) {
                Resource<?> resource = (Resource<?>) object;
                objectNode.addLinks(resource.getLinks());
                toUberData(objectNode, resource.getContent());
                return;
            } else if (object instanceof Resources) {
                Resources<?> resources = (Resources<?>) object;

                // TODO set name using EVO see HypermediaSupportBeanDefinitionRegistrar

                objectNode.addLinks(resources.getLinks());

                Collection<?> content = resources.getContent();
                toUberData(objectNode, content);
                return;
            } else if (object instanceof ResourceSupport) {
                ResourceSupport resource = (ResourceSupport) object;

                objectNode.addLinks(resource.getLinks());

                // wrap object attributes below to avoid endless loop

            } else if (object instanceof Collection) {
                Collection<?> collection = (Collection<?>) object;
                for (Object item : collection) {
                    // TODO name must be repeated for each collection item
                    UberNode itemNode = new UberNode();
                    objectNode.addData(itemNode);
                    toUberData(itemNode, item);

                    //                    toUberData(objectNode, item);
                }
                return;
            }
            if (object instanceof Map) {
                Map<?, ?> map = (Map<?, ?>) object;
                for (Entry<?, ?> entry : map.entrySet()) {
                    String key = entry.getKey().toString();
                    Object content = entry.getValue();
                    Object value = getContentAsScalarValue(content);
                    UberNode entryNode = new UberNode();
                    objectNode.addData(entryNode);
                    entryNode.setName(key);
                    if (value != null) {
                        entryNode.setValue(value);
                    } else {
                        toUberData(entryNode, content);
                    }
                }
            } else {
                PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(object);// BeanUtils
                // .getPropertyDescriptors(bean.getClass());
                for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                    String name = propertyDescriptor.getName();
                    if (filtered.contains(name)) {
                        continue;
                    }
                    UberNode propertyNode = new UberNode();
                    Object content = propertyDescriptor.getReadMethod().invoke(object);

                    Object value = getContentAsScalarValue(content);
                    propertyNode.setName(name);
                    objectNode.addData(propertyNode);
                    if (value != null) {
                        // for each scalar property of a simple bean, add valuepair nodes to data
                        propertyNode.setValue(value);
                    } else {
                        toUberData(propertyNode, content);
                    }
                }
            }
        } catch (Exception ex) {
            throw new RuntimeException("failed to transform object " + object, ex);
        }
    }

    private static PropertyDescriptor[] getPropertyDescriptors(Object bean) {
        try {
            return Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
        } catch (IntrospectionException e) {
            throw new RuntimeException("failed to get property descriptors of bean " + bean, e);
        }
    }

    private static Object getContentAsScalarValue(Object content) {
        final Object value;
        if (content == null) {
            value = UberNode.NULL_VALUE;
        } else if (DataType.isSingleValueType(content.getClass())) {
            value = content.toString();
        } else {
            value = null;
        }
        return value;
    }

    /**
     * Converts single link to uber node.
     *
     * @param href to use
     * @param actionDescriptor to use for action and model, never null
     * @param rels of the link
     * @return uber link
     */
    public static UberNode toUberLink(String href, ActionDescriptor actionDescriptor, String... rels) {
        return toUberLink(href, actionDescriptor, Arrays.asList(rels));
    }

    /**
     * Converts single link to uber node.
     *
     * @param href to use
     * @param actionDescriptor to use for action and model, never null
     * @param rels of the link
     * @return uber link
     */
    public static UberNode toUberLink(String href, ActionDescriptor actionDescriptor, List<String> rels) {
        Assert.notNull(actionDescriptor, "actionDescriptor must not be null");
        UberNode uberLink = new UberNode();
        uberLink.setRel(rels);
        PartialUriTemplateComponents partialUriTemplateComponents = new PartialUriTemplate(href)
                .expand(Collections.<String, Object>emptyMap());
        uberLink.setUrl(partialUriTemplateComponents.getBaseUri());
        uberLink.setModel(getModelProperty(href, actionDescriptor));
        if (actionDescriptor != null) {
            RequestMethod requestMethod = RequestMethod.valueOf(actionDescriptor.getHttpMethod());
            uberLink.setAction(UberAction.forRequestMethod(requestMethod));
        }
        return uberLink;
    }

    private static String getModelProperty(String href, ActionDescriptor actionDescriptor) {

        PartialUriTemplate uriTemplate = new PartialUriTemplate(href);
        RequestMethod httpMethod = RequestMethod.valueOf(actionDescriptor.getHttpMethod());
        final String model;
        switch (httpMethod) {
        case GET:
        case DELETE: {
            model = buildModel(uriTemplate.getVariableNames(), "{?", ",", "}", "%s");
            break;
        }
        case POST:
        case PUT:
        case PATCH: {
            model = buildModel(uriTemplate.getVariableNames(), "", "&", "", "%s={%s}");
            break;
        }
        default:
            model = null;
        }
        return StringUtils.isEmpty(model) ? null : model;
    }

    public static List<ActionDescriptor> getActionDescriptors(Link link) {
        List<ActionDescriptor> actionDescriptors;
        if (link instanceof Affordance) {
            actionDescriptors = ((Affordance) link).getActionDescriptors();
        } else {
            actionDescriptors = Arrays
                    .asList((ActionDescriptor) new SpringActionDescriptor("get", RequestMethod.GET.name()));
        }
        return actionDescriptors;
    }

    public static List<String> getRels(Link link) {
        List<String> rels;
        if (link instanceof Affordance) {
            rels = ((Affordance) link).getRels();
        } else {
            rels = Arrays.asList(link.getRel());
        }
        return rels;
    }

    private static String getUrlProperty(Link link) {
        PartialUriTemplateComponents partialUriTemplateComponents = new PartialUriTemplate(link.getHref())
                .expand(Collections.<String, Object>emptyMap());
        return partialUriTemplateComponents.getBaseUri();
        //      return UriComponentsBuilder.fromUriString(baseUri).build().normalize().toString();
    }

    private static String buildModel(List<String> variableNames, String prefix, String separator, String suffix,
            String parameterTemplate) {
        StringBuilder sb = new StringBuilder();
        for (String variable : variableNames) {
            if (sb.length() == 0) {
                sb.append(prefix);
            } else {
                sb.append(separator);
            }
            sb.append(String.format(parameterTemplate, variable, variable));
        }
        if (sb.length() > 0) {
            sb.append(suffix);
        }
        return sb.toString();
    }
}