com.orange.mmp.api.helpers.DefaultApiContainer.java Source code

Java tutorial

Introduction

Here is the source code for com.orange.mmp.api.helpers.DefaultApiContainer.java

Source

/*
 * Copyright (C) 2010 France Telecom
 *
 * 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.orange.mmp.api.helpers;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.xml.namespace.QName;

import org.apache.commons.collections.map.HashedMap;

import com.orange.mmp.api.MMPApiException;
import com.orange.mmp.api.ApiContainer;
import com.orange.mmp.api.ApiEvent;
import com.orange.mmp.api.ApiObserver;
import com.orange.mmp.core.ApplicationListener;
import com.orange.mmp.core.MMPException;
import com.orange.mmp.core.config.MMPConfig;
import com.orange.mmp.core.data.Element;
import com.orange.mmp.core.data.Module;
import com.orange.mmp.core.data.Api;
import com.orange.mmp.module.MMPModuleException;
import com.orange.mmp.module.ModuleContainerFactory;
import com.orange.mmp.module.ModuleEvent;
import com.orange.mmp.module.ModuleObserver;

/**
 * Default simple ApiContainer implementation
 * 
 * @author Thomas MILLET
 *
 */
public class DefaultApiContainer implements ApplicationListener, ApiContainer, ModuleObserver {

    /**
     * Attribute name used to define a class name
     */
    public static final QName CUAPI_CONFIG_ATTR_CLASSNAME = new QName("classname");

    /**
     * Attribute name used to define if a service is published on WEB API
     */
    public static final QName CUAPI_CONFIG_ATTR_IS_PUBLISHED = new QName("published");

    /**
     * Attribute name used to define if a service is shared between MMP instances
     */
    public static final QName CUAPI_CONFIG_ATTR_IS_SHARED = new QName("shared");

    /**
     * Attribute name used to define if a service is public on WEB API
     */
    public static final QName CUAPI_CONFIG_ATTR_IS_PUBLIC = new QName("public");

    /**
     * Attribute name used to define if a service is private on WEB API
     */
    public static final QName CUAPI_CONFIG_ATTR_IS_PRIVATE = new QName("private");

    /**
     * Attribute name used to define the service error type (body or http)
     */
    public static final QName CUAPI_CONFIG_ATTR_ERROR_TYPE = new QName("errortype");

    /**
     * Cache for services implementation
     */
    private Map<Api, Element> apiCache;

    /**
     * List of registered service observers
     */
    private List<ApiObserver> apiObservers;

    /*
     * (non-Javadoc)
     * @see com.orange.mmp.api.ApiContainer#addApi(com.orange.mmp.core.data.Api, java.lang.Object)
     */
    public Api addApi(Api api, Object apiImpl) throws MMPApiException {
        //Check if DefinitionClass is an interface
        if (!api.getDefinitionClass().isInterface()) {
            throw new MMPApiException("Definition class " + api.getDefinitionClass() + " of api " + api.getName()
                    + " is not an interface");
        }
        //List method of service for caching purpose
        HashedMap methodsMap = new HashedMap();
        for (Method method : api.getDefinitionClass().getMethods()) {
            // TODO Fix this to find a way to add multiple methods with same name
            //if(methodsMap.containsKey(method.getName())) throw new MMPApiException("Duplicated method name "+method.getName()+" in api "+api.getName());
            methodsMap.put(method.getName(), method);
        }

        synchronized (this.apiCache) {
            //Add it to service cache
            this.apiCache.put(api, new Element(api, new Element(apiImpl, methodsMap)));

            //Notify ServiceObservers of new service availability
            ApiEvent apiEvent = new ApiEvent(ApiEvent.API_ADDED, api);
            for (ApiObserver serviceObserver : this.apiObservers) {
                serviceObserver.onApiEvent(apiEvent);
            }
        }

        return api;
    }

    /* (non-Javadoc)
     * @see com.orange.mmp.api.ApiContainer#getApiMethod(com.orange.mmp.core.data.Api, java.lang.String)
     */
    public Method getApiMethod(Api api, String methodName) throws MMPApiException {
        if (this.apiCache.containsKey(api)) {
            Element apiElement = ((Element) ((Element) this.apiCache.get(api)).getValue());
            if (((HashedMap) apiElement.getValue()).containsKey(methodName)) {
                return (Method) ((HashedMap) apiElement.getValue()).get(methodName);
            } else
                throw new MMPApiException("Method '" + api.getName() + "." + methodName + "' not found");
        } else
            throw new MMPApiException("API '" + api.getName() + "' not found");
    }

    /*
     * (non-Javadoc)
     * @see com.orange.mmp.api.ApiContainer#invokeApi(com.orange.mmp.core.data.Api, java.lang.String, java.lang.Object[])
     */
    public Object invokeApi(Api api, String methodName, Object... params) throws MMPApiException {
        Object apiImplementation = this.getApiImplementation(api);
        Method method = this.getApiMethod(api, methodName);

        try {
            return method.invoke(apiImplementation, params);
        } catch (IllegalArgumentException iarge) {
            throw new MMPApiException(iarge);
        } catch (IllegalAccessException iae) {
            throw new MMPApiException(iae);
        } catch (InvocationTargetException ite) {
            throw new MMPApiException(ite.getCause());
        }
    }

    /*
     * (non-Javadoc)
     * @see com.orange.mmp.api.ApiContainer#getApi(com.orange.mmp.core.data.Api)
     */
    public Api getApi(Api api) throws MMPApiException {
        if (this.apiCache.containsKey(api)) {
            return (Api) ((Element) this.apiCache.get(api)).getKey();
        } else
            throw new MMPApiException("API '" + api.getName() + "' not found");
    }

    /*
     * (non-Javadoc)
     * @see com.orange.mmp.api.ApiContainer#getApiImplementation(com.orange.mmp.core.data.Api)
     */
    public Object getApiImplementation(Api api) throws MMPApiException {
        if (this.apiCache.containsKey(api)) {
            return ((Element) (Element) this.apiCache.get(api).getValue()).getKey();
        } else
            return null;
    }

    /*
     * (non-Javadoc)
     * @see com.orange.mmp.api.ApiContainer#listApis()
     */
    public List<Api> listApis() throws MMPApiException {
        List<Api> apiList = new ArrayList<Api>();
        apiList.addAll(this.apiCache.keySet());
        return apiList;
    }

    /*
     * (non-Javadoc)
     * @see com.orange.mmp.api.ApiContainer#removeApi(com.orange.mmp.core.data.Api)
     */
    public void removeApi(Api api) throws MMPApiException {
        synchronized (this.apiCache) {
            //Retrieve full API instance to build ServiceEvent
            ApiEvent apiEvent = new ApiEvent(ApiEvent.API_REMOVED, this.getApi(api));

            //Notify listeners
            for (ApiObserver apiObserver : this.apiObservers) {
                apiObserver.onApiEvent(apiEvent);
            }

            //Remove api
            this.apiCache.remove(api);
        }
    }

    public void initialize() throws MMPException {
        //Initialize API observers
        this.apiObservers = Collections.synchronizedList(new ArrayList<ApiObserver>());

        //Initialized API cache
        this.apiCache = new ConcurrentHashMap<Api, Element>();

        //Get the ModuleContainer and add itself as a ModuleObserver
        ModuleContainerFactory.getInstance().getModuleContainer().registerModuleObserver(this);
    }

    public void shutdown() throws MMPApiException {
        if (this.apiObservers != null)
            this.apiObservers.clear();
        if (this.apiCache != null)
            this.apiCache.clear();
    }

    /*
     * (non-Javadoc)
     * @see com.orange.mmp.module.ModuleObserver#onModuleEvent(com.orange.mmp.module.ModuleEvent)
     */
    public void onModuleEvent(ModuleEvent moduleEvent) {
        try {
            if (moduleEvent.getType() == ModuleEvent.MODULE_ADDED) {
                this.addModuleApi(moduleEvent.getModule());
            } else if (moduleEvent.getType() == ModuleEvent.MODULE_REMOVED) {
                this.removeModuleApi(moduleEvent.getModule());
            }
        } catch (MMPApiException cue) {
            //NOP - Just Log
        }
    }

    /**
     * Inner method used to add module API from their configuration file  
     * 
     * @param module The module owning the API
     * @throws MMPApiException
     */
    @SuppressWarnings("unchecked")
    protected void addModuleApi(Module module) throws MMPApiException {
        try {
            MMPConfig moduleConfiguration = ModuleContainerFactory.getInstance().getModuleContainer()
                    .getModuleConfiguration(module);
            if (moduleConfiguration != null && moduleConfiguration.getApi() != null) {
                for (MMPConfig.Api apiConfig : moduleConfiguration.getApi()) {
                    String definitionClassname = null;
                    String implementationClassname = null;
                    if (apiConfig.getDefinition() != null
                            && apiConfig.getDefinition().getOtherAttributes() != null) {
                        definitionClassname = apiConfig.getDefinition().getOtherAttributes()
                                .get(CUAPI_CONFIG_ATTR_CLASSNAME);
                    }
                    if (apiConfig.getImplementation() != null
                            && apiConfig.getImplementation().getOtherAttributes() != null) {
                        implementationClassname = apiConfig.getImplementation().getOtherAttributes()
                                .get(CUAPI_CONFIG_ATTR_CLASSNAME);
                    }

                    if (definitionClassname != null && implementationClassname != null) {
                        Class definitionClass = ModuleContainerFactory.getInstance().getModuleContainer()
                                .loadModuleClass(module, definitionClassname);
                        if (!definitionClass.isInterface()) {
                            throw new MMPApiException("Failed to add Module '" + module.getName() + "' Service : '"
                                    + definitionClass.getName() + "' is not an interface");
                        }
                        Object implementationInstance = ModuleContainerFactory.getInstance().getModuleContainer()
                                .loadModuleClass(module, implementationClassname).newInstance();
                        Api api = new Api();
                        api.setDefinitionClass(definitionClass);
                        api.setName(apiConfig.getName());
                        api.setPublished(apiConfig.getOtherAttributes().get(CUAPI_CONFIG_ATTR_IS_PUBLISHED) == null
                                || apiConfig.getOtherAttributes().get(CUAPI_CONFIG_ATTR_IS_PUBLISHED)
                                        .equalsIgnoreCase("true"));
                        api.setShared(apiConfig.getOtherAttributes().get(CUAPI_CONFIG_ATTR_IS_SHARED) != null
                                && apiConfig.getOtherAttributes().get(CUAPI_CONFIG_ATTR_IS_SHARED)
                                        .equalsIgnoreCase("true"));
                        api.setPublic(apiConfig.getOtherAttributes().get(CUAPI_CONFIG_ATTR_IS_PUBLIC) != null
                                && apiConfig.getOtherAttributes().get(CUAPI_CONFIG_ATTR_IS_PUBLIC)
                                        .equalsIgnoreCase("true"));
                        api.setPrivate(apiConfig.getOtherAttributes().get(CUAPI_CONFIG_ATTR_IS_PRIVATE) != null
                                && apiConfig.getOtherAttributes().get(CUAPI_CONFIG_ATTR_IS_PRIVATE)
                                        .equalsIgnoreCase("true"));

                        // Errortype
                        if (apiConfig.getOtherAttributes().get(CUAPI_CONFIG_ATTR_ERROR_TYPE) != null)
                            api.setErrorType(
                                    apiConfig.getOtherAttributes().get(CUAPI_CONFIG_ATTR_ERROR_TYPE).toLowerCase());
                        else
                            api.setErrorType("body");
                        //Add api to current ServiceContainer
                        this.addApi(api, implementationInstance);
                    }
                }
            }
        } catch (InstantiationException ie) {
            throw new MMPApiException(ie);
        } catch (IllegalAccessException iae) {
            throw new MMPApiException(iae);
        } catch (MMPModuleException ce) {
            throw new MMPApiException(ce);
        }
    }

    /**
     * Inner method used to remove a module API implementation
     * 
     * @param module The module owning the API
     * @param moduleContainer The module container
     * @throws MMPApiException
     */
    protected void removeModuleApi(Module module) throws MMPApiException {
        try {
            MMPConfig moduleConfiguration = ModuleContainerFactory.getInstance().getModuleContainer()
                    .getModuleConfiguration(module);
            if (moduleConfiguration != null && moduleConfiguration.getApi() != null) {
                for (MMPConfig.Api apiConfig : moduleConfiguration.getApi()) {
                    Api api = new Api();
                    api.setName(apiConfig.getName());
                    this.removeApi(api);
                }
            }
        } catch (MMPModuleException ce) {
            throw new MMPApiException(ce);
        }
    }

    public void registerApiObserver(ApiObserver apiObserver) throws MMPApiException {
        this.apiObservers.add(apiObserver);
    }

    public void unregisterApiObserver(ApiObserver apiObserver) throws MMPApiException {
        this.apiObservers.remove(apiObserver);
    }

}