com.wavemaker.runtime.service.ElementType.java Source code

Java tutorial

Introduction

Here is the source code for com.wavemaker.runtime.service.ElementType.java

Source

/*
 *  Copyright (C) 2012-2013 CloudJee, Inc. All rights reserved.
 *
 *  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.wavemaker.runtime.service;

import java.beans.PropertyDescriptor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.beanutils.PropertyUtils;
import org.springframework.util.ClassUtils;

import com.wavemaker.json.type.FieldDefinition;
import com.wavemaker.json.type.GenericFieldDefinition;
import com.wavemaker.json.type.ListTypeDefinition;
import com.wavemaker.json.type.OperationEnumeration;
import com.wavemaker.json.type.reflect.ListReflectTypeDefinition;
import com.wavemaker.json.type.reflect.ObjectReflectTypeDefinition;
import com.wavemaker.json.type.reflect.PrimitiveReflectTypeDefinition;
import com.wavemaker.json.type.reflect.ReflectTypeDefinition;
import com.wavemaker.json.type.reflect.ReflectTypeState;
import com.wavemaker.json.type.reflect.ReflectTypeUtils;

/**
 * Used by <code>ServiceDefinition</code> representing the operation's input and output type.
 * 
 * @author Frankie Fu
 */
public class ElementType implements Cloneable {

    private String name;

    private String javaType;

    private boolean isList;

    private boolean allowNull;

    private boolean supportsQuickData;

    private String subType; // salesforce

    private List<OperationEnumeration> require = new ArrayList<OperationEnumeration>();

    private List<OperationEnumeration> noChange = new ArrayList<OperationEnumeration>();

    private List<OperationEnumeration> exclude = new ArrayList<OperationEnumeration>();

    /**
     * The service this type is in (if null, assumed to be the current service).
     */
    private String service;

    private List<ElementType> properties = new ArrayList<ElementType>();

    // - only used by dataservice services - needs to be generalized and
    // refactored so individual services can set this on types
    // and then forget about it.
    // - do we only need this for the UI? if so, can we put this logic
    // somewhere else entirely?
    private boolean isTopLevel = false;

    public ElementType(String javaType) {
        this(null, javaType);
    }

    public ElementType(Class<?> javaType) {
        this(null, javaType);
    }

    public ElementType(String name, String javaType) {
        this(name, javaType, false);
    }

    public ElementType(String name, Class<?> javaType) {
        this(name, javaType, false);
    }

    public ElementType(String name, String javaType, boolean isList) {
        this.name = name;
        this.javaType = javaType;
        this.isList = isList;
    }

    /**
     * Create an ElementType with one level of children (populated by looking at the bean properties of javaType). This
     * method should not be used recursively.
     */
    public ElementType(String name, Class<?> javaType, boolean isList) {

        this(name, javaType.getName(), isList);

        PropertyDescriptor[] pds;

        pds = PropertyUtils.getPropertyDescriptors(javaType);

        List<ElementType> elements = new ArrayList<ElementType>(pds.length);
        for (PropertyDescriptor pd : pds) {
            if (pd.getName().equals("class")) {
                continue;
            }
            if (pd.getReadMethod() == null && pd.getWriteMethod() == null) {
                continue;
            }

            Class<?> klass;
            Type type;
            if (pd.getReadMethod() != null) {
                klass = pd.getReadMethod().getReturnType();
                type = pd.getReadMethod().getGenericReturnType();
            } else {
                klass = pd.getWriteMethod().getParameterTypes()[0];
                type = pd.getWriteMethod().getGenericParameterTypes()[0];
            }

            ElementType element;
            if (klass.isArray()) {
                element = new ElementType(pd.getName(), klass.getComponentType().getName(), true);
            } else if (Collection.class.isAssignableFrom(klass) && type instanceof ParameterizedType) {
                ParameterizedType ptype = (ParameterizedType) type;
                Type aType = ptype.getActualTypeArguments()[0];
                element = new ElementType(pd.getName(), ((Class<?>) aType).getName(), true);
            } else {
                element = new ElementType(pd.getName(), klass.getName());
            }

            elements.add(element);
        }
        this.properties = elements;
    }

    public ElementType(String name, String javaType, boolean isList, List<ElementType> properties) {
        this.name = name;
        this.javaType = javaType;
        this.isList = isList;
        this.properties = properties;
    }

    public ElementType(String name, Class<?> javaType, boolean isList, List<ElementType> properties) {
        this(name, javaType.getName(), isList, properties);
    }

    /**
     * Returns the name for this type.
     * 
     * @return The name for this type.
     */
    public String getName() {
        return this.name;
    }

    /**
     * Sets the name for this type.
     * 
     * @param name The name for this type.
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Returns the full name of the Java type.
     * 
     * @return Strings like "int", "java.lang.String", "java.io.File".
     */
    public String getJavaType() {
        return this.javaType;
    }

    /**
     * Sets the full name of the Java type.
     * 
     * @param javaType Strings like "int", "java.lang.String", "java.io.File".
     */
    public void setJavaType(String javaType) {
        this.javaType = javaType;
    }

    public boolean isList() {
        return this.isList;
    }

    public void setList(boolean isList) {
        this.isList = isList;
    }

    public List<ElementType> getProperties() {
        return this.properties;
    }

    public void addProperty(ElementType property) {
        this.properties.add(property);
    }

    public void setProperties(List<ElementType> properties) {
        this.properties = properties;
    }

    public String getService() {
        return this.service;
    }

    public void setService(String service) {
        this.service = service;
    }

    public boolean isTopLevel() {
        return this.isTopLevel;
    }

    public void setTopLevel(boolean isTopLevel) {
        this.isTopLevel = isTopLevel;
    }

    public boolean isAllowNull() {
        return this.allowNull;
    }

    public void setAllowNull(boolean allowNull) {
        this.allowNull = allowNull;
    }

    public String getSubType() {
        return this.subType;
    }

    public void setSubType(String subType) {
        this.subType = subType;
    }

    public boolean isSupportsQuickData() {
        return this.supportsQuickData;
    }

    public void setSupportsQuickData(boolean supportsQuickData) {
        this.supportsQuickData = supportsQuickData;
    }

    @Override
    public String toString() {
        return this.javaType;
    }

    public List<OperationEnumeration> getRequire() {
        return this.require;
    }

    public void setRequire(List<OperationEnumeration> require) {
        this.require = require;
    }

    public List<OperationEnumeration> getNoChange() {
        return this.noChange;
    }

    public void setNoChange(List<OperationEnumeration> noChange) {
        this.noChange = noChange;
    }

    public List<OperationEnumeration> getExclude() {
        return this.exclude;
    }

    public void setExclude(List<OperationEnumeration> exclude) {
        this.exclude = exclude;
    }

    /**
     * Transforms this ElementType into a FieldDefinition, to make the transition easier. This uses the default
     * reflection-based TypeDefinition classes ({@link com.wavemaker.json.type.reflect}).
     * 
     * @return
     */
    public FieldDefinition toFieldDefinition() {

        GenericFieldDefinition ret = new GenericFieldDefinition();

        Class<?> klass = null;
        try {
            if (getJavaType() != null) {
                klass = ClassUtils.forName(getJavaType());
            }
        } catch (ClassNotFoundException e) {
            // ignore
        }

        if (!getProperties().isEmpty()) {
            ObjectReflectTypeDefinition ortd = new ObjectReflectTypeDefinition();

            ortd.setTypeName(getJavaType());
            for (ElementType et : getProperties()) {
                ortd.getFields().put(et.getName(), et.toFieldDefinition());
            }

            ret.setTypeDefinition(ortd);
        } else if (klass != null) {
            ret = (GenericFieldDefinition) ReflectTypeUtils.getFieldDefinition(klass, new ReflectTypeState(), false,
                    null);
        } else {
            // for now, assume it's primitive and let it pass
            /*
             * System.out.println("Unhandled ET: "+this+" (javaType: "+
             * getJavaType()+", name: "+getName()+", properties: "+ getProperties()+")");
             */
            PrimitiveReflectTypeDefinition prtd = new PrimitiveReflectTypeDefinition();
            prtd.setTypeName(this.getJavaType());
            ret.setTypeDefinition(prtd);
        }

        if (ret.getTypeDefinition() != null) {
            ((ReflectTypeDefinition) ret.getTypeDefinition()).setLiveService(isSupportsQuickData());
            ((ReflectTypeDefinition) ret.getTypeDefinition()).setShortName(getName());
        }

        if (isList()) {
            List<ListTypeDefinition> listType = new ArrayList<ListTypeDefinition>();
            ListReflectTypeDefinition lrtd = new ListReflectTypeDefinition();
            lrtd.setKlass(List.class);
            lrtd.setTypeName(List.class.getName());
            listType.add(lrtd);
            ret.setArrayTypes(listType);
        }

        ret.setNoChange(getNoChange());
        ret.setExclude(getExclude());
        ret.setRequire(getRequire());
        ret.setName(getName());
        ret.setAllowNull(isAllowNull());
        ret.setSubType(getSubType()); // salesforce

        return ret;
    }

    @Override
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException ex) {
            throw new AssertionError(ex);
        }
    }
}