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

com.manywho.sdk.services.describe.AbstractDescribeService Maven / Gradle / Ivy

package com.manywho.sdk.services.describe;

import com.github.fge.lambdas.Throwing;
import com.manywho.sdk.entities.describe.DescribeServiceInstall;
import com.manywho.sdk.entities.describe.DescribeServiceResponse;
import com.manywho.sdk.entities.describe.DescribeValue;
import com.manywho.sdk.entities.describe.DescribeValueCollection;
import com.manywho.sdk.entities.draw.elements.type.TypeElementBinding;
import com.manywho.sdk.entities.draw.elements.type.TypeElementBindingCollection;
import com.manywho.sdk.entities.draw.elements.type.TypeElementCollection;
import com.manywho.sdk.entities.draw.elements.type.TypeElementProperty;
import com.manywho.sdk.entities.draw.elements.type.TypeElementPropertyBinding;
import com.manywho.sdk.entities.draw.elements.type.TypeElementPropertyBindingCollection;
import com.manywho.sdk.entities.draw.elements.type.TypeElementPropertyCollection;
import com.manywho.sdk.enums.ContentType;
import com.manywho.sdk.services.CachedData;
import com.manywho.sdk.services.annotations.Action;
import com.manywho.sdk.services.annotations.ActionInput;
import com.manywho.sdk.services.annotations.ActionOutput;
import com.manywho.sdk.services.annotations.TypeElement;
import com.manywho.sdk.services.annotations.TypeProperty;
import com.manywho.sdk.services.describe.actions.AbstractAction;
import com.manywho.sdk.services.describe.actions.ActionCollection;
import com.manywho.sdk.services.describe.actions.DefaultAction;
import com.manywho.sdk.services.describe.types.AbstractType;
import com.manywho.sdk.services.types.TypeParser;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public abstract class AbstractDescribeService implements DescribeService {
    @Override
    public boolean getProvidesAutoBinding() {
        return false;
    }

    @Override
    public boolean getProvidesDatabase() {
        return false;
    }

    @Override
    public boolean getProvidesFiles() {
        return false;
    }

    @Override
    public boolean getProvidesIdentity() {
        return false;
    }

    @Override
    public boolean getProvidesListening() {
        return false;
    }

    @Override
    public boolean getProvidesLogic() {
        return false;
    }

    @Override
    public boolean getProvidesNotifications() {
        return false;
    }

    @Override
    public boolean getProvidesSmartSave() {
        return false;
    }

    @Override
    public boolean getProvidesSocial() {
        return false;
    }

    @Override
    public boolean getProvidesSharing() {
        return false;
    }

    @Override
    public boolean getProvidesViews() {
        return false;
    }

    @Override
    public boolean getProvidesVoting() {
        return false;
    }

    @Override
    public ActionCollection createActions() throws IllegalAccessException, InstantiationException {
        ActionCollection actions = new ActionCollection();
        actions.addAll(buildActionsFromAbstractActions());
        actions.addAll(buildActionsFromAnnotatedActions());

        Collections.sort(actions);

        return actions;
    }

    @Override
    public DescribeServiceInstall createInstall() throws IllegalAccessException, InstantiationException {
        TypeElementCollection typeElements = new TypeElementCollection();
        typeElements.addAll(buildTypeElementsFromAbstractTypes());
        typeElements.addAll(buildTypeElementsFromAnnotatedTypes());

        Collections.sort(typeElements);

        return new DescribeServiceInstall(typeElements);
    }

    @Override
    public DescribeServiceResponse createResponse() throws Exception {
        return new DescribeServiceResponse() {{
            setCulture(AbstractDescribeService.this.createCulture());
            setConfigurationValues(AbstractDescribeService.this.createConfigurationValues());
            setProvidesAutoBinding(AbstractDescribeService.this.getProvidesAutoBinding());
            setProvidesDatabase(AbstractDescribeService.this.getProvidesDatabase());
            setProvidesFiles(AbstractDescribeService.this.getProvidesFiles());
            setProvidesIdentity(AbstractDescribeService.this.getProvidesIdentity());
            setProvidesListening(AbstractDescribeService.this.getProvidesListening());
            setProvidesLogic(AbstractDescribeService.this.getProvidesLogic());
            setProvidesNotifications(AbstractDescribeService.this.getProvidesNotifications());
            setProvidesSmartSave(AbstractDescribeService.this.getProvidesSmartSave());
            setProvidesSocial(AbstractDescribeService.this.getProvidesSocial());
            setProvidesSharing(AbstractDescribeService.this.getProvidesSharing());
            setProvidesViews(AbstractDescribeService.this.getProvidesViews());
            setProvidesVoting(AbstractDescribeService.this.getProvidesVoting());
            setActions(AbstractDescribeService.this.createActions());
            setInstall(AbstractDescribeService.this.createInstall());
        }};
    }

    private ActionCollection buildActionsFromAbstractActions() {
        final Set> actions = CachedData.reflections
                .getSubTypesOf(AbstractAction.class);

        if (CollectionUtils.isNotEmpty(actions)) {
            return actions.stream()
                    .map(Throwing.function(Class::newInstance))
                    .collect(Collectors.toCollection(ActionCollection::new));
        }

        return new ActionCollection();
    }

    private ActionCollection buildActionsFromAnnotatedActions() {
        final Set> actions = CachedData.reflections.getTypesAnnotatedWith(Action.class);

        if (CollectionUtils.isNotEmpty(actions)) {
            final Set annotatedInputs = CachedData.reflections.getFieldsAnnotatedWith(ActionInput.class);
            final Set annotatedOutputs = CachedData.reflections.getFieldsAnnotatedWith(ActionOutput.class);

            return actions.stream()
                    .map(action -> buildActionFromAnnotatedAction(action, annotatedInputs, annotatedOutputs))
                    .collect(Collectors.toCollection(ActionCollection::new));
        }

        return new ActionCollection();
    }

    private com.manywho.sdk.services.describe.actions.Action buildActionFromAnnotatedAction(Class annotatedAction, Set annotatedInputs, Set annotatedOutputs) {
        Action action = annotatedAction.getAnnotation(Action.class);

        // Build the list of inputs for the action
        DescribeValueCollection inputs = annotatedInputs.stream()
                .filter(field -> field.getDeclaringClass().equals(annotatedAction))
                .map(Throwing.function(field -> createActionInputFromField(action, field)))
                .sorted()
                .collect(Collectors.toCollection(DescribeValueCollection::new));

        // Build the list of outputs for the action
        DescribeValueCollection outputs = annotatedOutputs.stream()
                .filter(field -> field.getDeclaringClass().equals(annotatedAction))
                .map(Throwing.function(field -> createActionOutputFromField(action, field)))
                .sorted()
                .collect(Collectors.toCollection(DescribeValueCollection::new));

        return new DefaultAction(action.uriPart(), action.name(), action.summary(), inputs, outputs);
    }

    private DescribeValue createActionInputFromField(Action action, Field field) throws Exception {
        ActionInput input = field.getAnnotation(ActionInput.class);

        return createActionValueFromField(action.name(), field, input.contentType(), input.name(), input.required(), input.referencedType());
    }

    private DescribeValue createActionOutputFromField(Action action, Field field) throws Exception {
        ActionOutput output = field.getAnnotation(ActionOutput.class);

        return createActionValueFromField(action.name(), field, output.contentType(), output.name(), output.required(), output.referencedType());
    }

    private DescribeValue createActionValueFromField(String actionName, Field field, ContentType contentType, String name, boolean required, Class referencedType) throws Exception {
        DescribeValue input = new DescribeValue();
        input.setContentType(contentType);
        input.setDeveloperName(name);
        input.setRequired(required);

        if (contentType.equals(ContentType.Object) || contentType.equals(ContentType.List)) {
            input.setTypeElementDeveloperName(TypeParser.getReferencedTypeName(actionName, field, referencedType, name, contentType));
        }

        return input;
    }

    private TypeElementCollection buildTypeElementsFromAbstractTypes() {
        final Set> types = CachedData.reflections
                .getSubTypesOf(AbstractType.class);

        // Loop over all the classes that extend AbstractType, instantiate, then add them into a TypeElementCollection
        if (CollectionUtils.isNotEmpty(types)) {
            return types.stream()
                    .map(Throwing.function(type -> (com.manywho.sdk.entities.draw.elements.type.TypeElement) type.newInstance()))
                    .collect(Collectors.toCollection(TypeElementCollection::new));
        }

        return new TypeElementCollection();
    }

    private TypeElementCollection buildTypeElementsFromAnnotatedTypes() {
        final Set> types = CachedData.reflections.getTypesAnnotatedWith(TypeElement.class);

        if (CollectionUtils.isNotEmpty(types)) {
            final Set annotatedProperties = CachedData.reflections.getFieldsAnnotatedWith(TypeProperty.class);

            return types.stream()
                    .map(type -> buildTypeElementFromAnnotatedType(type, annotatedProperties))
                    .collect(Collectors.toCollection(TypeElementCollection::new));
        }

        return new TypeElementCollection();
    }

    private com.manywho.sdk.entities.draw.elements.type.TypeElement buildTypeElementFromAnnotatedType(Class annotatedType, Set annotatedProperties) {
        TypeElement typeElement = annotatedType.getAnnotation(TypeElement.class);

        // Build a list of ManyWho Properties created from the annotated fields in the type passed in
        TypeElementPropertyCollection properties = annotatedProperties.stream()
                .filter(field -> field.getDeclaringClass().equals(annotatedType))
                .map(Throwing.function(field -> createTypeElementProperty(typeElement.name(), field)))
                .sorted()
                .collect(Collectors.toCollection(TypeElementPropertyCollection::new));

        TypeElementPropertyBindingCollection propertyBindings = annotatedProperties.stream()
                .filter(field -> field.getDeclaringClass().equals(annotatedType))
                .map(field -> field.getAnnotation(TypeProperty.class))
                .filter(TypeProperty::bound)
                .map(property -> new TypeElementPropertyBinding(property.name(), property.name()))
                .sorted()
                .collect(Collectors.toCollection(TypeElementPropertyBindingCollection::new));

        // Create the default summary value, if one wasn't provided
        String typeElementSummary = typeElement.summary();
        if (StringUtils.isEmpty(typeElementSummary)) {
            typeElementSummary = "The " + typeElement.name() + " object structure";
        }

        TypeElementBindingCollection bindings = null;

        // Only add the binding if there are properties that are set to bound
        if (CollectionUtils.isNotEmpty(propertyBindings)) {
            bindings = new TypeElementBindingCollection();
            bindings.add(new TypeElementBinding(typeElement.name(), typeElementSummary, typeElement.name(), propertyBindings));
        }

        return new com.manywho.sdk.entities.draw.elements.type.TypeElement(typeElement.name(), typeElementSummary, properties, bindings);
    }

    /**
     * @param typeElementName the name of the type element the property is defined in
     * @param propertyField the field that the property is defined as in the type
     * @return a new property containing the values from the given annotations
     * @throws Exception when a referenced type could not be found
     */
    private TypeElementProperty createTypeElementProperty(String typeElementName, Field propertyField) throws Exception {
        TypeProperty property = propertyField.getAnnotation(TypeProperty.class);

        String referencedTypeName = null;

        // If the type property annotation is of Object or List, then we need to find the typeElementName of the referenced type
        if (property.contentType().equals(ContentType.Object) || property.contentType().equals(ContentType.List)) {
            referencedTypeName = TypeParser.getReferencedTypeName(typeElementName, propertyField, property);
        }

        // Return a new TypeElementProperty with the values from annotations
        return new TypeElementProperty(property.name(), property.contentType(), referencedTypeName);
    }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy