com.wavemaker.tools.javaservice.JavaServiceDefinition.java Source code

Java tutorial

Introduction

Here is the source code for com.wavemaker.tools.javaservice.JavaServiceDefinition.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.tools.javaservice;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.springframework.core.io.Resource;

import com.wavemaker.common.MessageResource;
import com.wavemaker.common.WMRuntimeException;
import com.wavemaker.common.util.ClassLoaderUtils;
import com.wavemaker.json.type.FieldDefinition;
import com.wavemaker.json.type.PrimitiveTypeDefinition;
import com.wavemaker.json.type.TypeDefinition;
import com.wavemaker.json.type.TypeState;
import com.wavemaker.json.type.reflect.ReflectTypeDefinition;
import com.wavemaker.json.type.reflect.ReflectTypeState;
import com.wavemaker.json.type.reflect.ReflectTypeUtils;
import com.wavemaker.runtime.javaservice.JavaServiceType;
import com.wavemaker.runtime.pws.IPwsServiceModifier;
import com.wavemaker.runtime.server.ServerUtils;
import com.wavemaker.runtime.service.LiveDataService;
import com.wavemaker.runtime.service.ServiceType;
import com.wavemaker.runtime.service.definition.ReflectServiceDefinition;
import com.wavemaker.runtime.service.definition.ServiceOperation;

/**
 * @author Simon Toens
 * @author Matt Small
 * @author Jeremy Grelle
 */
public class JavaServiceDefinition implements ReflectServiceDefinition {

    private final String serviceId;

    private final List<TypeDefinition> typeDefinitions = new ArrayList<TypeDefinition>();

    private final List<ServiceOperation> operations = new ArrayList<ServiceOperation>();

    private final List<String> excludeTypeNames;

    private boolean implementsCRUDService = false;

    private String packageName = null;

    private String serviceClassName = null;

    public JavaServiceDefinition() {
        this.serviceId = "";
        this.excludeTypeNames = null;
    }

    /**
     * Normal constructor. Attempts to use reflection (and a custom, very isolated classloader) to read information
     * about the class.
     * 
     * @throws IOException
     */
    public JavaServiceDefinition(String serviceClassName, String serviceId, Resource serviceCompiledDir,
            Resource serviceLibDir, List<String> excludeTypeNames)
            throws ClassNotFoundException, LinkageError, IOException {

        this(serviceClassName, serviceId,
                serviceCompiledDir == null ? null : Arrays.asList(new File[] { serviceCompiledDir.getFile() }),
                serviceLibDir == null ? null : Arrays.asList(new File[] { serviceLibDir.getFile() }),
                excludeTypeNames);
    }

    /**
     * Normal constructor. Attempts to use reflection (and a custom, very isolated classloader) to read information
     * about the class.
     */
    @SuppressWarnings("unchecked")
    public JavaServiceDefinition(String serviceClassName, String serviceId, List<File> serviceCompiledDirs,
            List<File> serviceLibDirs, List<String> excludeTypeNames) throws ClassNotFoundException, LinkageError {

        List<File> classpath = new ArrayList<File>();
        if (serviceCompiledDirs != null) {
            classpath.addAll(serviceCompiledDirs);
        }
        if (serviceLibDirs != null) {
            for (File serviceLibDir : serviceLibDirs) {
                if (!serviceLibDir.exists()) {
                    continue;
                } else if (!serviceLibDir.isDirectory()) {
                    throw new WMRuntimeException(MessageResource.LIB_DIR_NOT_DIR, serviceLibDir);
                }

                classpath.addAll(FileUtils.listFiles(serviceLibDir, new String[] { "jar" }, false));
            }
        }

        ClassLoader cl = ClassLoaderUtils.getTempClassLoaderForFile(classpath.toArray(new File[] {}));

        Class<?> serviceClass = ClassLoaderUtils.loadClass(serviceClassName, false, cl);
        Class<?> runtimeServiceClass = ClassLoaderUtils.loadClass("com.wavemaker.runtime.service.LiveDataService",
                cl);

        this.serviceId = serviceId;
        this.excludeTypeNames = excludeTypeNames;

        init(serviceClass, runtimeServiceClass);
    }

    /**
     * A constructor that reads information from the serviceClass class parameter.
     */
    public JavaServiceDefinition(Class<?> serviceClass, String serviceId) {

        this.serviceId = serviceId;
        this.excludeTypeNames = new ArrayList<String>();

        init(serviceClass, LiveDataService.class);
    }

    /**
     * A constructor that reads information from the serviceClass class parameter.
     */
    public JavaServiceDefinition(String serviceClass, String serviceId) {
        this.serviceClassName = serviceClass;
        this.serviceId = serviceId;
        this.excludeTypeNames = new ArrayList<String>();
    }

    public static String getRelPathFromClass(String fqClassName) {
        return fqClassName.replace('.', '/') + ".java";
    }

    public static String getClass(String fqClassName) {

        String ret;

        if (fqClassName.contains(".")) {
            ret = fqClassName.substring(fqClassName.lastIndexOf('.') + 1);
        } else {
            ret = fqClassName;
        }

        return ret;
    }

    public static String getPackage(String fqClassName) {

        String ret = null;

        if (fqClassName.contains(".")) {
            ret = fqClassName.substring(0, fqClassName.lastIndexOf('.'));
        }

        return ret;
    }

    private void init(Class<?> serviceClass, Class<?> runtimeServiceClass) {

        ReflectTypeState typeState = new ReflectTypeState();

        Collection<Method> methods = filterOverloadedMethods(ServerUtils.getClientExposedMethods(serviceClass));
        for (Method m : methods) {
            initOperation(m, typeState);
        }

        this.implementsCRUDService = runtimeServiceClass.isAssignableFrom(serviceClass);
        this.serviceClassName = serviceClass.getName();

        if (this.implementsCRUDService) {
            for (TypeDefinition td : this.typeDefinitions) {
                ((ReflectTypeDefinition) td).setLiveService(this.implementsCRUDService);
            }
        }

        if (serviceClass.getPackage() == null) {
            this.packageName = null;
        } else {
            this.packageName = serviceClass.getPackage().getName();
        }
    }

    private void initOperation(Method method, TypeState typeState) {

        ServiceOperation so = new ServiceOperation();
        so.setName(method.getName());

        if (!method.getReturnType().equals(void.class)) {
            so.setReturnType(ReflectTypeUtils.getFieldDefinition(method, typeState, false, null));
            checkAddType(so.getReturnType().getTypeDefinition());
        }

        List<String> paramNames = ServerUtils.getParameterNames(method);
        Type[] types = method.getGenericParameterTypes();
        List<FieldDefinition> params = new ArrayList<FieldDefinition>(types.length);
        so.setParameterTypes(params);
        for (int i = 0; i < types.length; i++) {
            params.add(ReflectTypeUtils.getFieldDefinition(types[i], typeState, false, paramNames.get(i)));
            checkAddType(params.get(i).getTypeDefinition());
        }

        this.operations.add(so);
    }

    private void checkAddType(TypeDefinition td) {

        if (td == null) {
            return;
        }
        if (this.typeDefinitions.contains(td)) {
            return;
        }
        if (td instanceof PrimitiveTypeDefinition) {
            return;
        }

        for (TypeDefinition knownType : this.typeDefinitions) {
            if (knownType.getTypeName().equals(td.getTypeName())) {
                return;
            }
        }

        if (this.excludeTypeNames.contains(td.getTypeName())) {
            return;
        }

        this.typeDefinitions.add(td);
    }

    /**
     * Get a list of methods, excluding overloaded ones, biased towards the method with the least number of arguments
     * (in other words, if a method is overloaded, the instance with the fewest arguments is included in the return
     * value).
     * 
     * @param allMethods
     * @return
     */
    public static Collection<Method> filterOverloadedMethods(List<Method> allMethods) {

        Map<String, Method> methodsMap = new HashMap<String, Method>();
        for (Method method : allMethods) {
            if (methodsMap.containsKey(method.getName())) {
                if (methodsMap.get(method.getName()).getParameterTypes().length > method
                        .getParameterTypes().length) {
                    methodsMap.put(method.getName(), method);
                }
            } else {
                methodsMap.put(method.getName(), method);
            }
        }

        return methodsMap.values();
    }

    @Override
    public String getPackageName() {
        return this.packageName;
    }

    public void setPackageName(String packageName) {
        this.packageName = packageName;
    }

    @Override
    public String getServiceId() {
        return this.serviceId;
    }

    @Override
    public ServiceType getServiceType() {
        return new JavaServiceType();
    }

    @Override
    public String getRuntimeConfiguration() {
        return null;
    }

    @Override
    public String getServiceClass() {
        return this.serviceClassName;
    }

    @Override
    public List<String> getEventNotifiers() {
        return Collections.emptyList();
    }

    @Override
    public boolean isLiveDataService() {
        return this.implementsCRUDService;
    }

    public void setLiveDataService(boolean liveDataService) {
        this.implementsCRUDService = liveDataService;
    }

    @Override
    public List<TypeDefinition> getLocalTypes() {
        return this.typeDefinitions;
    }

    @Override
    public List<TypeDefinition> getLocalTypes(String username, String password) { // salesforce
        return null;
    }

    @Override
    public List<ServiceOperation> getServiceOperations() {
        return this.operations;
    }

    @Override
    public String getPartnerName() {
        return null;
    }

    @Override
    public List<ServiceOperation> getServiceOperations(IPwsServiceModifier serviceModifier) {
        return this.operations;
    }
}