org.hyperic.hq.api.transfer.impl.ResourceTransferImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.hyperic.hq.api.transfer.impl.ResourceTransferImpl.java

Source

/*
 * NOTE: This copyright does *not* cover user programs that use Hyperic
 * program services by normal system calls through the application
 * program interfaces provided as part of the Hyperic Plug-in Development
 * Kit or the Hyperic Client Development Kit - this is merely considered
 * normal use of the program, and does *not* fall under the heading of
 * "derived work".
 *
 * Copyright (C) [2004-2012], VMware, Inc.
 * This file is part of Hyperic.
 *
 * Hyperic is free software; you can redistribute it and/or modify
 * it under the terms version 2 of the GNU General Public License as
 * published by the Free Software Foundation. This program is distributed
 * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA.
 */
package org.hyperic.hq.api.transfer.impl;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PostConstruct;
import javax.ws.rs.core.Response;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hq.agent.AgentConnectionException;
import org.hyperic.hq.api.model.ConfigurationTemplate;
import org.hyperic.hq.api.model.ConfigurationValue;
import org.hyperic.hq.api.model.MetricTemplate;
import org.hyperic.hq.api.model.PropertyList;
import org.hyperic.hq.api.model.ResourceConfig;
import org.hyperic.hq.api.model.ResourceDetailsType;
import org.hyperic.hq.api.model.ResourceModel;
import org.hyperic.hq.api.model.ResourceStatusType;
import org.hyperic.hq.api.model.ResourceTypeModel;
import org.hyperic.hq.api.model.Resources;
import org.hyperic.hq.api.model.common.ExternalRegistrationStatus;
import org.hyperic.hq.api.model.common.RegistrationID;
import org.hyperic.hq.api.model.measurements.HttpEndpointDefinition;
import org.hyperic.hq.api.model.resources.ComplexIp;
import org.hyperic.hq.api.model.resources.RegisteredResourceBatchResponse;
import org.hyperic.hq.api.model.resources.ResourceBatchResponse;
import org.hyperic.hq.api.model.resources.ResourceFilterRequest;
import org.hyperic.hq.api.services.impl.ApiMessageContext;
import org.hyperic.hq.api.transfer.NotificationsTransfer;
import org.hyperic.hq.api.transfer.ResourceTransfer;
import org.hyperic.hq.api.transfer.mapping.ConfigurationTemplateMapper;
import org.hyperic.hq.api.transfer.mapping.ExceptionToErrorCodeMapper;
import org.hyperic.hq.api.transfer.mapping.MetricTemplateMapper;
import org.hyperic.hq.api.transfer.mapping.ResourceDetailsTypeStrategy;
import org.hyperic.hq.api.transfer.mapping.ResourceMapper;
import org.hyperic.hq.api.transfer.mapping.UnknownEndpointException;
import org.hyperic.hq.appdef.Ip;
import org.hyperic.hq.appdef.server.session.AppdefResource;
import org.hyperic.hq.appdef.server.session.Platform;
import org.hyperic.hq.appdef.server.session.Server;
import org.hyperic.hq.appdef.shared.AppdefEntityConstants;
import org.hyperic.hq.appdef.shared.AppdefEntityID;
import org.hyperic.hq.appdef.shared.AppdefEntityNotFoundException;
import org.hyperic.hq.appdef.shared.AppdefResourceValue;
import org.hyperic.hq.appdef.shared.AppdefUtil;
import org.hyperic.hq.appdef.shared.CPropManager;
import org.hyperic.hq.appdef.shared.ConfigFetchException;
import org.hyperic.hq.appdef.shared.ConfigManager;
import org.hyperic.hq.appdef.shared.InvalidConfigException;
import org.hyperic.hq.appdef.shared.IpManager;
import org.hyperic.hq.appdef.shared.PlatformManager;
import org.hyperic.hq.appdef.shared.PlatformNotFoundException;
import org.hyperic.hq.appdef.shared.PlatformValue;
import org.hyperic.hq.appdef.shared.Property;
import org.hyperic.hq.appdef.shared.ServerValue;
import org.hyperic.hq.appdef.shared.ServiceValue;
import org.hyperic.hq.auth.shared.SessionNotFoundException;
import org.hyperic.hq.auth.shared.SessionTimeoutException;
import org.hyperic.hq.authz.server.session.AuthzSubject;
import org.hyperic.hq.authz.server.session.Resource;
import org.hyperic.hq.authz.shared.AuthzConstants;
import org.hyperic.hq.authz.shared.PermissionException;
import org.hyperic.hq.authz.shared.PermissionManager;
import org.hyperic.hq.authz.shared.PermissionManagerFactory;
import org.hyperic.hq.authz.shared.ResourceManager;
import org.hyperic.hq.autoinventory.AutoinventoryException;
import org.hyperic.hq.bizapp.server.session.ProductBossImpl.ConfigSchemaAndBaseResponse;
import org.hyperic.hq.bizapp.shared.AllConfigResponses;
import org.hyperic.hq.bizapp.shared.AppdefBoss;
import org.hyperic.hq.bizapp.shared.ProductBoss;
import org.hyperic.hq.common.ApplicationException;
import org.hyperic.hq.common.NotFoundException;
import org.hyperic.hq.common.ObjectNotFoundException;
import org.hyperic.hq.common.shared.HQConstants;
import org.hyperic.hq.context.Bootstrap;
import org.hyperic.hq.measurement.server.session.MeasurementTemplate;
import org.hyperic.hq.measurement.shared.MeasurementManager;
import org.hyperic.hq.notifications.DefaultEndpoint;
import org.hyperic.hq.notifications.HttpEndpoint;
import org.hyperic.hq.notifications.NotificationEndpoint;
import org.hyperic.hq.notifications.filtering.Filter;
import org.hyperic.hq.notifications.filtering.FilterChain;
import org.hyperic.hq.notifications.filtering.FilteringCondition;
import org.hyperic.hq.notifications.filtering.ResourceDestinationEvaluator;
import org.hyperic.hq.notifications.model.InventoryNotification;
import org.hyperic.hq.product.PluginException;
import org.hyperic.hq.product.PluginNotFoundException;
import org.hyperic.hq.product.ProductPlugin;
import org.hyperic.hq.product.shared.ProductManager;
import org.hyperic.hq.scheduler.ScheduleWillNeverFireException;
import org.hyperic.util.Transformer;
import org.hyperic.util.config.ConfigResponse;
import org.hyperic.util.config.ConfigSchema;
import org.hyperic.util.config.EncodingException;
import org.hyperic.util.timer.StopWatch;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.ConversionServiceFactory;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.transaction.annotation.Transactional;

public class ResourceTransferImpl implements ResourceTransfer {

    private static final Log log = LogFactory.getLog(ResourceTransferImpl.class);

    private static final String IP_MAC_ADDRESS_KEY = "IP_MAC_ADDRESS";

    private ResourceManager resourceManager;
    private ResourceMapper resourceMapper;
    private ProductBoss productBoss;
    private CPropManager cpropManager;
    private AppdefBoss appdepBoss;
    private PlatformManager platformManager;
    private ExceptionToErrorCodeMapper errorHandler;
    private ResourceDestinationEvaluator evaluator;
    private ConfigManager configManager;
    private IpManager ipManager;
    protected NotificationsTransfer notificationsTransfer;
    protected ProductManager productManager;
    protected MeasurementManager measurementManager;
    protected ConfigurationTemplateMapper configTemplateMapper;
    @Autowired
    protected MetricTemplateMapper metricTemplateMapper;
    protected PermissionManager permissionManager;

    @Autowired
    public ResourceTransferImpl(ResourceManager resourceManager, ResourceMapper resourceMapper,
            ProductBoss productBoss, CPropManager cpropManager, AppdefBoss appdepBoss,
            PlatformManager platformManager, final ConfigurationTemplateMapper configTemplateMapper,
            ExceptionToErrorCodeMapper errorHandler, ResourceDestinationEvaluator evaluator,
            ConfigManager configManager, IpManager ipManager, ProductManager productManager,
            MeasurementManager measurementManager) {
        this.resourceManager = resourceManager;
        this.resourceMapper = resourceMapper;
        this.productBoss = productBoss;
        this.cpropManager = cpropManager;
        this.appdepBoss = appdepBoss;
        this.platformManager = platformManager;
        this.configTemplateMapper = configTemplateMapper;
        this.errorHandler = errorHandler;
        this.evaluator = evaluator;
        this.configManager = configManager;
        this.ipManager = ipManager;
        this.productManager = productManager;
        this.measurementManager = measurementManager;
        this.permissionManager = PermissionManagerFactory.getInstance();
    }//EOM

    @PostConstruct
    public void init() {
        this.notificationsTransfer = (NotificationsTransfer) Bootstrap.getBean("notificationsTransfer");
    }

    public final ResourceModel getResource(ApiMessageContext messageContext, final String platformNaturalID,
            final ResourceTypeModel resourceType, final ResourceStatusType resourceStatusType,
            final int hierarchyDepth, final ResourceDetailsType[] responseMetadata)
            throws SessionNotFoundException, SessionTimeoutException, ObjectNotFoundException {
        AuthzSubject authzSubject = messageContext.getAuthzSubject();
        if (resourceStatusType == ResourceStatusType.AUTO_DISCOVERED) {
            return this.getAIResource(platformNaturalID, resourceType, hierarchyDepth, responseMetadata);
        } else {
            return this.getResourceInner(
                    new Context(authzSubject, platformNaturalID, resourceType, responseMetadata, this),
                    hierarchyDepth);
        } //EO else if approved resource 
    }//EOM

    /**
     * Note: AI resources are unsupported 
     * @param platformID
     * @param resourceStatusType
     * @param hierarchyDepth
     * @param responseMetadata
     * @return
     * @throws ObjectNotFoundException 
     */
    public final ResourceModel getResource(ApiMessageContext messageContext, final String platformID,
            final ResourceStatusType resourceStatusType, final int hierarchyDepth,
            final ResourceDetailsType[] responseMetadata) throws ObjectNotFoundException {
        AuthzSubject authzSubject = messageContext.getAuthzSubject();
        if (resourceStatusType == ResourceStatusType.AUTO_DISCOVERED) {
            throw new UnsupportedOperationException("AI Resource load by internal ID is unsupported");
        } else {
            return this.getResourceInner(new Context(authzSubject, platformID, responseMetadata, this),
                    hierarchyDepth);
        } //EO else if approved resource type 

    }//EOM 

    /**
      * @param hierarchyDepth
     * @return
     * @throws ObjectNotFoundException 
     */
    private final ResourceModel getResourceInner(final Context flowContext, int hierarchyDepth)
            throws ObjectNotFoundException {

        ResourceModel currentResource = null;
        try {
            //derive the resource type load strategy using the resource type enum 
            //Note: of the resourceType is null, then the generic resource resource type 
            //would be used 
            final ResourceTypeStrategy resourceTypeStrategy = ResourceTypeStrategy
                    .valueOf(flowContext.resourceType);

            //if the resource Type is null then find by internal id else natural id  
            flowContext.setBackendResource(resourceTypeStrategy.getResource(flowContext));

            //populate the response resource (excluding the children)
            for (ResourceDetailsTypeStrategy resourceDetailType : flowContext.resourceDetails) {
                resourceDetailType.populateResource(flowContext);
            } //EO while there are more resource details 

            //if resource root was not yet initialized do so now 
            //if(flowContext.resourceRoot == null) flowContext.resourceRoot = flowContext.currResource ; 
            currentResource = flowContext.currResource;

            //starts from 1 
            if (--hierarchyDepth > 0) {
                //populate the resource's children 
                final List<Resource> listBackendResourceChildren = this.resourceManager
                        .findChildren(flowContext.subject, flowContext.backendResource);

                ResourceModel resourceChild = null;
                for (Resource backendResourceChild : listBackendResourceChildren) {
                    flowContext.reset();

                    //set the child in the flow's backend resource 
                    flowContext.setBackendResource(backendResourceChild);
                    flowContext.resourceType = ResourceTypeModel
                            .valueOf(backendResourceChild.getResourceType().getAppdefType());
                    resourceChild = this.getResourceInner(flowContext, hierarchyDepth);
                    currentResource.addSubResource(resourceChild);

                } //EO while there are more children 

            } //EOM 

        } catch (ObjectNotFoundException e) {
            throw e;
        } catch (Throwable t) {
            throw (t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t));
        } //EO catch block 

        return currentResource;

    }//EOM

    public final ResourceBatchResponse approveResource(ApiMessageContext messageContext,
            final Resources aiResources) {
        //NYI 
        return null;
    }//EOM 

    @Transactional(readOnly = false)
    public final ResourceBatchResponse updateResources(ApiMessageContext messageContext,
            final Resources resources) {

        final ResourceBatchResponse response = new ResourceBatchResponse(this.errorHandler);

        //iterate over the resources and for each resource, update the following metadata if exists and changed:
        //TODO: if no resources where provided (null or empty) should an excpetion be thrown? 
        final List<ResourceModel> resourcesList = resources.getResources();
        if (resourcesList == null)
            return response;
        String resourceID = null;
        final int noOfInputResources = resourcesList.size();
        ResourceModel inputResource = null;
        ResourceConfig resourceConfig = null;

        AuthzSubject authzSubject = messageContext.getAuthzSubject();
        final Context flowContext = new Context(authzSubject, this);

        int failureCounter = 0;
        for (int i = 0; i < noOfInputResources; i++) {

            try {
                inputResource = resourcesList.get(i);
                flowContext.setInputResource(inputResource);

                //find the backend resource using the resource Type (if null then find by internal id else natural id)
                //not need to check for null backendResource as exception should have been thrown if the resource 
                //could not have been loaded
                final ResourceTypeStrategy resourceTypeStrategy = ResourceTypeStrategy
                        .valueOf(inputResource.getResourceType());

                flowContext.setBackendResource(resourceTypeStrategy.getResource(flowContext));
                flowContext.resourceTypeStrategy = resourceTypeStrategy;

                //map the input into the backend resource (resource metadata update
                this.resourceMapper.mergeResource(inputResource, flowContext.backendResource, flowContext);

                //if there are properties to update do so now
                resourceConfig = inputResource.getResourceConfig();
                if (resourceConfig != null && resourceConfig.getMapProps() != null)
                    this.updateResourceConfig(flowContext, resourceConfig);

            } catch (Throwable t) {
                this.errorHandler.log(t);

                resourceID = ResourceTypeStrategy.getResourceIdentifier(flowContext.currResource);
                String description = resourceID, additionalDescription = null;

                if (t instanceof NumberFormatException) {
                    description = "Resource ID " + resourceID;
                } //EO if number format 
                else if (t instanceof InvalidConfigException) {
                    additionalDescription = t.getMessage();
                } //EO else if InvalidConfigException

                response.addFailedResource(t, resourceID, additionalDescription /*additional Description*/,
                        description);
                resourceID = null;
                failureCounter++;
            } finally { //EO catch block
                flowContext.reset();
            } //EO catch block 

        } //EO while there are more resources

        //if the failure counter == no of input resources, raise an error rather than returning success with failed resources section 
        if (failureCounter == noOfInputResources) {
            throw this.errorHandler.newWebApplicationException(new Throwable(),
                    Response.Status.INTERNAL_SERVER_ERROR, ExceptionToErrorCodeMapper.ErrorCode.UPDATE_FAILURE,
                    ". Failed to update all " + noOfInputResources + " input resources.");
        } //EO if overall update failuer 

        return response;
    }//EOM 

    /**
     * 
     * Note: AI resource updates are unsupported 
     * Note: Currently all-or-nothing.
     * 
     * @param flowContext
     * @param resourceConfig
     * @throws EncodingException
     * @throws PluginNotFoundException
     * @throws PluginException
     * @throws ScheduleWillNeverFireException
     * @throws ApplicationException
     * @throws AutoinventoryException
     * @throws AgentConnectionException
     */
    private final void updateResourceConfig(final Context flowContext, final ResourceConfig resourceConfig)
            throws EncodingException, PluginNotFoundException, PluginException, ScheduleWillNeverFireException,
            ApplicationException, AutoinventoryException, AgentConnectionException {

        final Resource resource = flowContext.backendResource;
        final AppdefEntityID entityID = flowContext.entityID = AppdefUtil.newAppdefEntityId(resource);

        //load existing resource config data 
        this.initResourceConfig(flowContext);

        //merge cprops 
        final Resource prototype = resource.getPrototype();
        final int appdefTypeID = resource.getResourceType().getAppdefType();

        Object oldValue = null;
        String sKey = null, sNewValue = null;

        //iterate over the new config properties and search for a match in the following config sub systems 
        // - cprops 
        // - config response 
        //if not found in the above, store the value so that a user response may contain a list of unset (new) properties 
        final Map<String, String> configValues = resourceConfig.getMapProps();
        final List<String> listUnmatchedConfigProperties = new ArrayList<String>(configValues.size());

        //config resource modifications 
        final AllConfigResponses allConfigs = new AllConfigResponses(), rollbackConfigs = new AllConfigResponses();
        rollbackConfigs.setResource(allConfigs.setResource(entityID));

        final int iNoOfConfigurableTypes = ProductPlugin.CONFIGURABLE_TYPES.length;
        final ConfigResponse[] newConfigResponses = new ConfigResponse[iNoOfConfigurableTypes];

        ConfigSchemaAndBaseResponse configResponse = null;
        ConfigSchema configSchema = null;
        ConfigResponse currConfigData = null, newConfigData = null;
        boolean bKeySupported = false, bOverallKeySupported = false, bHadConfigResponsesChanged = false;

        for (Map.Entry<String, String> entry : configValues.entrySet()) {

            sKey = entry.getKey();
            sNewValue = entry.getValue();

            if (flowContext.cprops != null) {
                oldValue = flowContext.cprops.get(sKey);

                if ((bKeySupported = flowContext.cprops.containsKey(sKey))
                        && (oldValue == null || !oldValue.equals(sNewValue))) {
                    this.cpropManager.setValue(entityID, appdefTypeID, sKey, sNewValue);
                } //EO if the property exists and the value is different 
            } //EO if there were cprops associated with the resource 

            for (int i = 0; i < iNoOfConfigurableTypes; i++) {

                configResponse = flowContext.configResponses[i];

                if (configResponse == null) {
                    rollbackConfigs.setSupports(i, false);
                } else {
                    allConfigs.setSupports(i, true);
                    rollbackConfigs.setSupports(i, true);
                    rollbackConfigs.setConfig(i, configResponse.getResponse());

                    newConfigData = newConfigResponses[i];
                    if (newConfigData == null) {
                        newConfigData = newConfigResponses[i] = new ConfigResponse();
                        allConfigs.setConfig(i, newConfigData);
                    } //EO if not yet initialized 

                    currConfigData = configResponse.getResponse();
                    oldValue = currConfigData.getValue(sKey);

                    //if the current configResponse contains the key and the value is different, 
                    //override with the new value else ignore

                    if ((bKeySupported = (oldValue != null || currConfigData.supportsOption(sKey)))
                            && (oldValue == null || !oldValue.equals(sNewValue))) {
                        newConfigData.setValue(sKey, sNewValue);
                        bHadConfigResponsesChanged = true;
                        allConfigs.setShouldConfig(i, true);
                    } //EO if the config option was provided and was different than the current 

                    bOverallKeySupported = (bOverallKeySupported || bKeySupported);

                } //EO else if config data was defined 

            } //EO while there are more config resources

            //if !bConfigChanged then the key was not supported and should be discarded 
            if (!bOverallKeySupported)
                listUnmatchedConfigProperties.add(sKey);

            //reset the overall key support flag 
            bOverallKeySupported = false;

        } //EO while there are more new entries 

        //only store the configResponse if modifications were made 
        if (bHadConfigResponsesChanged) {
            //allConfigs.setEnableRuntimeAIScan(true) ;  
            //rollbackConfigs.setEnableRuntimeAIScan(true); 
            this.appdepBoss.setAllConfigResponses(flowContext.subject, allConfigs, rollbackConfigs, true);
        } //EO if there was a change 

        //TODO: pojo fields modifications 
    }//EOM 

    public final void initResourceVirtualData(final Context flowContext)
            throws ConfigFetchException, EncodingException, PluginNotFoundException, PluginException,
            PermissionException, AppdefEntityNotFoundException {
        flowContext.cprops = cpropManager.getEntries(flowContext.entityID);
    }

    public final Object initResourceConfig(final Context flowContext)
            throws ConfigFetchException, EncodingException, PluginNotFoundException, PluginException,
            PermissionException, AppdefEntityNotFoundException {

        final int iNoOfConfigTypes = ProductPlugin.CONFIGURABLE_TYPES.length;
        ConfigSchemaAndBaseResponse configMetadata = null;

        //load all resource related config metadata&data resources
        String configurableType = null;
        for (int i = 0; i < iNoOfConfigTypes; i++) {
            configurableType = ProductPlugin.CONFIGURABLE_TYPES[i];
            try {
                flowContext.configResponses[i] = configMetadata = productBoss.getConfigSchemaAndBaseResponse(
                        flowContext.subject, flowContext.entityID, configurableType, false/*validateFlow*/);
                //init the schema map in the config response so as to support key recognition validation 
                configMetadata.getResponse().setSchema(configMetadata.getSchema());
            } catch (PluginNotFoundException pnfe) {
                log.debug("Plugin Config Schema of type: " + configurableType + " was not defined for resource "
                        + flowContext.entityID);
            } //EO catch block 
              // XXX why are we catching an NPE???
            catch (NullPointerException npe) {
                npe.printStackTrace();
            }
        } //EO while there are more configurable types

        //load all cprop metadata
        final Resource prototype = flowContext.backendResource.getPrototype();

        flowContext.cprops = cpropManager.getEntries(flowContext.entityID);

        //TODO: pojo members data 

        return null;
    }//EOM 

    public ConfigurationTemplate getConfigurationTemplate(ApiMessageContext apiMessageContext, String resourceID)
            throws SessionTimeoutException, SessionNotFoundException, AppdefEntityNotFoundException,
            ConfigFetchException, PermissionException {

        final ResourceDetailsType[] detailsType = { ResourceDetailsType.BASIC };

        final AuthzSubject authzSubject = apiMessageContext.getAuthzSubject();
        final Integer sessionId = apiMessageContext.getSessionId();

        final Resource resource = ResourceTypeStrategy.RESOURCE
                .getResourceByInternalID(new Context(authzSubject, resourceID, detailsType, this));

        final int numConfigTypes = ProductPlugin.CONFIGURABLE_TYPES.length;

        ConfigurationTemplate configTemplate = null;
        // load all prototype related config metadata
        String configurableType = null;
        for (int i = 0; i < numConfigTypes; i++) {
            configurableType = ProductPlugin.CONFIGURABLE_TYPES[i];
            try {
                if (resourceIsPrototype(resource)) {
                    final String protototypeName = resource.getName();

                    final Map<String, ConfigSchema> configurations = this.productBoss
                            .getConfigSchemas(protototypeName, configurableType);
                    // Add to the existing configTemplate
                    configTemplate = this.configTemplateMapper.toConfigurationTemplate(configurations,
                            configurableType, configTemplate);
                } else {// if resource is not a prototype

                    final AppdefEntityID entityID = AppdefUtil.newAppdefEntityId(resource);

                    try {
                        ConfigSchema config = this.productBoss.getConfigSchema(sessionId, entityID,
                                configurableType);
                        // Add to the existing configTemplate
                        configTemplate = this.configTemplateMapper.toConfigurationTemplate(config, configurableType,
                                configTemplate);
                    } catch (EncodingException e) {
                        throw new ConfigFetchException(e, ProductPlugin.CONFIGURABLE_TYPES[i], entityID);
                    }

                } // EO if resource is not a prototype
            } catch (PluginException e) {
                // not all plugins have all config types
                log.debug("Plugin config not found for config type " + configurableType, e);
            }
        } // EO while there are more configTypes
        return configTemplate;
    }// EOM

    public List<MetricTemplate> getMetricTemplates(ApiMessageContext apiMessageContext, String resourceID)
            throws ObjectNotFoundException, SessionTimeoutException, SessionNotFoundException, PermissionException {
        final ResourceDetailsType[] detailsType = { ResourceDetailsType.BASIC };

        final AuthzSubject authzSubject = apiMessageContext.getAuthzSubject();
        final Integer sessionId = apiMessageContext.getSessionId();

        final Resource resource = ResourceTypeStrategy.RESOURCE
                .getResourceByInternalID(new Context(authzSubject, resourceID, detailsType, this));

        Collection<MeasurementTemplate> measurementTemplates;
        if (resourceIsPrototype(resource)) {
            measurementTemplates = measurementManager.getTemplatesByPrototype(resource);
        } else {// if resource is not a prototype
            throw new UnsupportedOperationException(
                    "Currently this operation is supported for resource prototypes only.");
        } // EO if resource is not a prototype
        List<MetricTemplate> metricTemplates = this.metricTemplateMapper.toMetricTemplates(resource,
                measurementTemplates);
        return metricTemplates;
    }// EOM

    private boolean resourceIsPrototype(final org.hyperic.hq.authz.server.session.Resource resource) {

        String name = resource.getResourceType().getName();

        return AuthzConstants.platformPrototypeTypeName.equals(name)
                || AuthzConstants.serverPrototypeTypeName.equals(name)
                || AuthzConstants.servicePrototypeTypeName.equals(name);

    }//EOM

    public enum ResourceTypeStrategy {

        PLATFORM(AppdefEntityConstants.APPDEF_TYPE_PLATFORM, PlatformValue.class) {

            @Override
            final Resource getResourceByNaturalID(final Context flowContext)
                    throws PlatformNotFoundException, PermissionException {
                final Platform platform = flowContext.visitor.getPlatformManager()
                        .findPlatformByFqdn(flowContext.subject, flowContext.naturalID);
                flowContext.resourceInstance = platform;
                return platform.getResource();
            }//EOM 

            @Override
            protected final AppdefResourceValue loadExistingDTO(final AppdefBoss appdefBoss,
                    final Context flowContext) throws Exception {
                Platform platform = (Platform) flowContext.resourceInstance;

                if (platform == null) {
                    flowContext.resourceInstance = platform = flowContext.getVisitor().getPlatformManager()
                            .findPlatformById(flowContext.backendResource.getInstanceId());
                } //EO else if platform was not yet loaded

                final PlatformValue platformDTO = new PlatformValue();
                platformDTO.setId(platform.getId());
                platformDTO.setFqdn(platform.getFqdn());
                platformDTO.setName(platform.getName());
                return platformDTO;
            }//EOM 

            @Override
            protected final AppdefResourceValue mergeResource(final Map<String, String> inputProps,
                    Map<String, PropertyList> oneToManyProps, AppdefResourceValue existingDTO,
                    final Context flowContext) throws Exception {

                PropertyList requetsIps = null;

                if ((requetsIps = oneToManyProps.get(IP_MAC_ADDRESS_KEY)) != null) {
                    if (requetsIps != null) {
                        //else determine whether the ips have changed
                        Platform platform = (Platform) flowContext.resourceInstance;

                        existingDTO = flowContext.visitor.getResourceMapper().mergePlatformIPs(existingDTO,
                                requetsIps.getProperties(), platform);

                    } //EO if ips were provided 
                } //EO if propertyList was defined 

                return existingDTO;
            }//EOM 

            @Override
            protected final void updateResourceInstance(final AppdefResourceValue newDTO,
                    final AppdefBoss appdefBoss, final AuthzSubject subject) throws Exception {
                appdefBoss.updatePlatform(subject, (PlatformValue) newDTO);
            }//EOM 

        }, //EO PLATFORM
        SERVER(AppdefEntityConstants.APPDEF_TYPE_SERVER, ServerValue.class) {

            @Override
            protected final AppdefResourceValue loadExistingDTO(final AppdefBoss appdefBoss,
                    final Context flowContext) throws Exception {
                AppdefResourceValue existingDTO = null;

                if (flowContext.resourceInstance == null) {
                    final Integer serverId = flowContext.backendResource.getInstanceId();
                    existingDTO = appdefBoss.findById(flowContext.subject, AppdefEntityID.newServerID(serverId));
                } else {
                    existingDTO = ((Server) flowContext.resourceInstance).getServerValue();
                } //EO else if the backend resource was loaded 

                return existingDTO;
            }//EOM 

            protected final void updateResourceInstance(final AppdefResourceValue newDTO,
                    final AppdefBoss appdefBoss, final AuthzSubject subject) throws Exception {
                appdefBoss.updateServer(subject, (ServerValue) newDTO, null/*cprops*/);
            }//EOM 

        }, //EO SERVER 
        SERVICE(AppdefEntityConstants.APPDEF_TYPE_SERVICE, ServiceValue.class) {
            protected AppdefResourceValue loadExistingDTO(final AppdefBoss appdefBoss, final Context flowContext)
                    throws Exception {
                final Integer serviceId = flowContext.backendResource.getInstanceId();
                return appdefBoss.findById(flowContext.subject, AppdefEntityID.newServiceID(serviceId));
            }//EOM 

            protected final void updateResourceInstance(final AppdefResourceValue newDTO,
                    final AppdefBoss appdefBoss, final AuthzSubject subject) throws Exception {
                appdefBoss.updateService(subject, (ServiceValue) newDTO, null/*cprops*/);
            }//EOM
        }, //EO SERVER
        RESOURCE(-999) {

        };//EO RESOURCE

        /**
         * 
         * @param resourceID naturalID/internal ID 
         * @param resourceManager
         * @return
         */
        Resource getResourceByNaturalID(final Context flowContext) throws Exception {
            throw new UnsupportedOperationException(
                    "Resource Of Type " + this.name() + " does not support find by natural ID");
        }//EOM 

        Resource getResourceByInternalID(final Context flowContext) {
            final int iInternalResourceID = Integer.parseInt(flowContext.internalID);
            return flowContext.visitor.getResourceManager().findResourceById(iInternalResourceID);
        }//EOM

        Resource getResource(final Context flowContext) throws Exception {
            Resource resource = null;

            if (flowContext.backendResource != null) {
                resource = flowContext.backendResource;
            } else if (flowContext.internalID != null) {
                resource = this.getResourceByInternalID(flowContext);
            } else {
                resource = this.getResourceByNaturalID(flowContext);
            } //EO else if internal id was not provided

            return resource;
        }//EOM

        public void mergeResource(final Context flowContext) throws Exception {
            final ResourceConfig resourceConfig = flowContext.currResource.getResourceConfig();
            if (this.clsAppdefResourceValue == null || resourceConfig == null)
                return;

            final AppdefBoss appdefBoss = flowContext.getVisitor().getAppdefBoss();

            //else if the resource config section was provided in the request
            AppdefResourceValue existingDTO = null;
            final Map<String, String> inputProps = resourceConfig.getMapProps();

            if (inputProps != null) {

                //load the existing AppdefResourceValue 
                existingDTO = this.loadExistingDTO(appdefBoss, flowContext);

                String value = null;
                Object oValue = null;
                ;
                Object[] metadata = null;
                Method method = null;

                for (Map.Entry<String, Object[]> entry : this.cachedPropertiesMutators.entrySet()) {

                    if ((value = inputProps.get(entry.getKey())) != null) {
                        metadata = entry.getValue();
                        method = (Method) metadata[0];

                        //convert the value into the target type 
                        oValue = conversionService.convert(value, STRING_DESCRIPTOR, (TypeDescriptor) metadata[1]);
                        method.invoke(existingDTO, oValue);

                    } //EO if input was provided for the given attribute  
                }
            } //EO if the inputProps was not null 

            //now check whether there are multi-property section in the request and if 
            //so delegate to sub-classes 
            final Map<String, PropertyList> oneToManyProps = resourceConfig.getMapListProps();
            if (oneToManyProps != null) {

                //if the existingDTO was not yet loaded (i.e. no one-one properties 
                //do so now 
                if (existingDTO == null) {
                    existingDTO = this.loadExistingDTO(appdefBoss, flowContext);
                } //EO the dtos were not yet initialized 

                this.mergeResource(inputProps, oneToManyProps, existingDTO, flowContext);
            } //EO if there were oneToManyProps for the given resource in the request

            //finally, if a DTO was created (i.e. potential modifications were found) 
            //invoke the respective udpateXXX 
            if (existingDTO != null)
                this.updateResourceInstance(existingDTO, appdefBoss, flowContext.subject);

        }//EOM

        protected AppdefResourceValue loadExistingDTO(final AppdefBoss appdefBoss, final Context flowContext)
                throws Exception {
            throw new UnsupportedOperationException();
        }//EOM 

        protected AppdefResourceValue mergeResource(final Map<String, String> inputProps,
                Map<String, PropertyList> oneToManyProps, final AppdefResourceValue existingDTO,
                final Context flowContext) throws Exception {
            return existingDTO;
        }//EOM 

        protected void updateResourceInstance(final AppdefResourceValue newDTO, final AppdefBoss appdefBoss,
                final AuthzSubject subject) throws Exception {
            throw new UnsupportedOperationException();
        }//EOM 

        private final static GenericConversionService conversionService = ConversionServiceFactory
                .createDefaultConversionService();
        private final static TypeDescriptor STRING_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
        private static final ResourceTypeStrategy[] cachedValues;
        private static final int iNoOfStrategies;

        private int appdefEntityType;
        private Class<? extends AppdefResourceValue> clsAppdefResourceValue;
        private Map<String, Object[]> cachedPropertiesMutators;

        static {
            cachedValues = values();
            iNoOfStrategies = cachedValues.length;
        }//EO static block

        private final void initCachedPropertiesMutators() {
            final Method[] methods = this.clsAppdefResourceValue.getDeclaredMethods();
            Property propertyMetadata = null;

            try {
                for (Method method : methods) {
                    propertyMetadata = method.getAnnotation(Property.class);
                    if (propertyMetadata != null) {
                        method.setAccessible(true);
                        this.cachedPropertiesMutators.put(propertyMetadata.value(),
                                new Object[] { method, TypeDescriptor.valueOf(method.getParameterTypes()[0]) });
                    } //EO if defined 
                } //EO while there are more declared methods
            } catch (Throwable t) {
                t.printStackTrace();
                throw new Error("Failed to initialize cachedPropertiesMutators for type " + this.name()
                        + " from class " + this.clsAppdefResourceValue, t);
            } //EO catch block 
        }//EOM 

        private ResourceTypeStrategy(final int appdefEntityType,
                final Class<? extends AppdefResourceValue> clsAppdefResourceValue) {
            this(appdefEntityType);
            this.clsAppdefResourceValue = clsAppdefResourceValue;
            if (clsAppdefResourceValue != null) {
                this.cachedPropertiesMutators = new ConcurrentHashMap<String, Object[]>();
                this.initCachedPropertiesMutators();
            } //EO if the clsAppdefesourceValue was not null 
        }//EOM 

        private ResourceTypeStrategy(final int appdefEntityType) {
            this.appdefEntityType = appdefEntityType;
        }//EOM 

        static final ResourceTypeStrategy valueOf(final int iStrategyType) {
            return (iStrategyType >= iNoOfStrategies ? RESOURCE : cachedValues[iStrategyType]);
        }//EOM 

        static final ResourceTypeStrategy valueOf(final ResourceTypeModel enumResourceType) {
            return (enumResourceType == null ? RESOURCE : valueOf(enumResourceType.name()));
        }//EOM 

        static final String getResourceIdentifier(final ResourceModel resource) {
            final String resourceIdentifier = resource.getId();
            return (resourceIdentifier == null || resourceIdentifier.isEmpty() ? resource.getNaturalID()
                    : resourceIdentifier);
        }//EOM 

    }//EOE 

    private final ResourceModel getAIResource(final String platformNaturalID, final ResourceTypeModel resourceType,
            final int hierarchyDepth, final ResourceDetailsType[] responseMetadata) {
        //TODO: NYI 
        return null;
    }//EOM 

    public final static class Context {
        public Resource backendResource;
        public AppdefResource resourceInstance;
        public AppdefEntityID entityID;
        public AuthzSubject subject;
        public ConfigSchemaAndBaseResponse[] configResponses;
        public Properties cprops;
        public ResourceTypeStrategy resourceTypeStrategy;

        public ResourceTransfer visitor;
        public String internalID;
        public String naturalID;
        public ResourceTypeModel resourceType;
        public Set<ResourceDetailsTypeStrategy> resourceDetails;
        public ResourceModel currResource;
        //Resource resourceRoot ; 

        public Context(final AuthzSubject subject, final String naturalID, final ResourceTypeModel resourceType,
                final ResourceDetailsType[] responseMetadata, final ResourceTransfer visitor) {
            this(subject, null/*internalID*/, responseMetadata, visitor);
            this.naturalID = naturalID;
            this.resourceType = resourceType;
        }//EOM

        Context(final AuthzSubject subject, final String internalID, final ResourceDetailsType[] responseMetadata,
                final ResourceTransfer visitor) {
            this(subject, visitor);
            this.internalID = internalID;
            this.resourceDetails = ResourceDetailsTypeStrategy.valueOf(responseMetadata);
        }//EOM 

        Context(final AuthzSubject subject, final ResourceTransfer visitor) {
            this.subject = subject;
            this.visitor = visitor;
            this.configResponses = new ConfigSchemaAndBaseResponse[ProductPlugin.CONFIGURABLE_TYPES.length];
        }//EOM

        public final void setBackendResource(final Resource backendResource) {
            this.backendResource = backendResource;
            this.internalID = backendResource.getId() + "";
        }//EOM 

        public final void setInputResource(final ResourceModel inputResource) {
            this.currResource = inputResource;
            this.internalID = inputResource.getId();
            this.naturalID = inputResource.getNaturalID();
        }//EOM 

        public final void reset() {
            this.backendResource = null;
            this.internalID = null;
            this.entityID = null;
            this.cprops = null;
            this.configResponses = new ConfigSchemaAndBaseResponse[ProductPlugin.CONFIGURABLE_TYPES.length];
            this.resourceType = null;
            this.naturalID = null;
            this.currResource = null;
            this.resourceInstance = null;
            this.resourceTypeStrategy = null;
        }//EOM 

        public ResourceTransfer getVisitor() {
            return this.visitor;
        }

    }//EO inner class Context 

    @Transactional(readOnly = true)
    public RegisteredResourceBatchResponse getResources(ApiMessageContext messageContext,
            ResourceDetailsType[] responseMetadata, int hierarchyDepth)
            throws PermissionException, NotFoundException {
        final boolean debug = log.isDebugEnabled();
        final StopWatch watch = new StopWatch();
        final RegisteredResourceBatchResponse res = new RegisteredResourceBatchResponse(errorHandler);
        if (responseMetadata == null) {
            log.warn("illegal request");
            throw errorHandler.newWebApplicationException(Response.Status.BAD_REQUEST,
                    ExceptionToErrorCodeMapper.ErrorCode.BAD_REQ_BODY);
        }
        final List<ResourceDetailsType> responseMetadataList = Arrays.asList(responseMetadata);
        if (hierarchyDepth < 0) {
            log.warn("hierarchy Depth cannot be < 0");
            throw errorHandler.newWebApplicationException(Response.Status.NOT_ACCEPTABLE,
                    ExceptionToErrorCodeMapper.ErrorCode.BAD_REQ_BODY);
        }
        final AuthzSubject authzSubject = messageContext.getAuthzSubject();
        if (debug)
            watch.markTimeBegin("findViewablePSSResources");
        final Set<Integer> viewable = permissionManager.findViewablePSSResources(authzSubject);
        if (debug)
            watch.markTimeEnd("findViewablePSSResources");
        final List<Resource> platformResources = getPlatformsFromResourceIds(viewable);
        if (debug)
            watch.markTimeBegin("getResourceToChildren");
        final Map<Resource, Collection<Resource>> resourceToChildren = getResourceToChildren(viewable,
                platformResources, hierarchyDepth);
        if (debug)
            watch.markTimeEnd("getResourceToChildren");
        if (debug)
            watch.markTimeBegin("getResourceConfig");
        final Map<Resource, ConfigResponse> config = getResourceConfig(authzSubject, responseMetadataList,
                resourceToChildren.keySet());
        if (debug)
            watch.markTimeEnd("getResourceConfig");
        final Map<Resource, Collection<Ip>> ipInfo = getIpInfo(responseMetadataList, platformResources);
        if (debug)
            watch.markTimeBegin("getResourceConfigProps");
        final Map<AppdefEntityID, Properties> cProps = getResourceConfigProps(responseMetadataList);
        if (debug)
            watch.markTimeEnd("getResourceConfigProps");
        final List<ResourceModel> resources = new ArrayList<ResourceModel>(platformResources.size());
        for (final Resource platformResource : platformResources) {
            ResourceModel model = resourceMapper.toResource(platformResource);
            resources.add(model);
            setAllChildren(model, platformResource, resourceToChildren, config, cProps, ipInfo);
        }
        res.setResources(resources);
        if (debug)
            log.debug(watch);
        return res;
    }

    private Map<AppdefEntityID, Properties> getResourceConfigProps(List<ResourceDetailsType> responseMetadataList) {
        if (!responseMetadataList.contains(ResourceDetailsType.VIRTUALDATA)
                && !responseMetadataList.contains(ResourceDetailsType.ALL)) {
            return Collections.emptyMap();
        }
        return cpropManager.getAllEntries(HQConstants.VCUUID, HQConstants.MOID);
    }

    private Map<Resource, Collection<Ip>> getIpInfo(List<ResourceDetailsType> responseMetadataList,
            Collection<Resource> platformResources) {
        if (!responseMetadataList.contains(ResourceDetailsType.PROPERTIES)
                && !responseMetadataList.contains(ResourceDetailsType.ALL)) {
            return Collections.emptyMap();
        }
        return ipManager.getIps(platformResources);
    }

    private Map<Resource, ConfigResponse> getResourceConfig(AuthzSubject subject,
            List<ResourceDetailsType> responseMetadataList, Set<Resource> resources) {
        if (!responseMetadataList.contains(ResourceDetailsType.PROPERTIES)
                && !responseMetadataList.contains(ResourceDetailsType.ALL)) {
            return Collections.emptyMap();
        }
        return configManager.getConfigResponses(resources, true);
    }

    private void setAllChildren(ResourceModel model, Resource platformResource,
            Map<Resource, Collection<Resource>> resourceToChildren, Map<Resource, ConfigResponse> config,
            Map<AppdefEntityID, Properties> cProps, Map<Resource, Collection<Ip>> ipInfo) {
        Collection<Resource> tmp;
        addResourceConfig(platformResource, model, config, cProps, ipInfo);
        if (null == (tmp = resourceToChildren.get(platformResource)) || tmp.isEmpty()) {
            return;
        }
        for (final Resource child : tmp) {
            final ResourceModel childModel = resourceMapper.toResource(child);
            model.addSubResource(childModel);
            setAllChildren(childModel, child, resourceToChildren, config, cProps, ipInfo);
        }
    }

    private void addResourceConfig(Resource r, ResourceModel resourceModel, Map<Resource, ConfigResponse> configMap,
            Map<AppdefEntityID, Properties> cProps, Map<Resource, Collection<Ip>> ipInfo) {
        final ConfigResponse configResponse = configMap.get(r);
        @SuppressWarnings("unchecked")
        final Map<String, String> config = (configResponse == null) ? new HashMap<String, String>()
                : configResponse.getConfig();
        final AppdefEntityID aeid = AppdefUtil.newAppdefEntityId(r);
        Properties properties = cProps.get(aeid);
        properties = (properties == null) ? new Properties() : properties;
        Object prop = properties.get(HQConstants.VCUUID);
        if (prop != null) {
            config.put(HQConstants.VCUUID, prop.toString());
        }
        prop = properties.get(HQConstants.MOID);
        if (prop != null) {
            config.put(HQConstants.MOID, prop.toString());
        }
        ResourceConfig resourceConfig = resourceModel.getResourceConfig();
        resourceConfig = (resourceConfig == null) ? new ResourceConfig() : resourceConfig;
        resourceConfig.setMapProps(config);
        resourceModel.setResourceConfig(resourceConfig);
        final Collection<Ip> ips = ipInfo.get(r);
        if (ips != null && !ips.isEmpty()) {
            Collection<ConfigurationValue> ipValues = new ArrayList<ConfigurationValue>(ips.size());
            for (Ip ip : ips) {
                ipValues.add(new ComplexIp(ip.getNetmask(), ip.getMacAddress(), ip.getAddress()));
            }
            resourceConfig.putMapListProps(IP_MAC_ADDRESS_KEY, ipValues);
        }
    }

    @SuppressWarnings("unchecked")
    private Map<Resource, Collection<Resource>> getResourceToChildren(Set<Integer> viewable,
            List<Resource> platformResources, int hierarchyDepth) {
        final List<Resource> currResources = new ArrayList<Resource>(platformResources);
        final Map<Resource, Collection<Resource>> rtn = new HashMap<Resource, Collection<Resource>>();
        for (Resource r : platformResources) {
            rtn.put(r, Collections.EMPTY_LIST);
        }
        final Map<Resource, Resource> systemResources = new HashMap<Resource, Resource>();
        for (int i = 2; i <= hierarchyDepth; i++) {
            final Map<Resource, Collection<Resource>> childResources = resourceManager
                    .findChildResources(currResources, viewable, true);
            rtn.putAll(childResources);
            currResources.removeAll(childResources.keySet());
            for (Resource r : currResources) {
                rtn.put(r, new ArrayList<Resource>(0));
            }
            currResources.clear();
            for (final Entry<Resource, Collection<Resource>> entry : childResources.entrySet()) {
                final Resource parent = entry.getKey();
                final Collection<Resource> children = entry.getValue();
                for (final Iterator<Resource> it = children.iterator(); it.hasNext();) {
                    final Resource child = it.next();
                    currResources.add(child);
                    // EMPTY_LIST usage is a place holder to avoid extra overhead where resources don't have child
                    // resources
                    rtn.put(child, Collections.EMPTY_LIST);
                    // remove place-holder resource so that Platform Services don't expose our internal implementation
                    // rather than exposing the system resource which is a place-holder
                    // In other words:
                    // desired output is "Platform --> Services"
                    // in HQ we store this relationship as "Platform --> System Server --> Services"
                    if (child.isSystem()) {
                        systemResources.put(child, parent);
                        it.remove();
                    }
                }
            }
        }
        // need to post process the data in order to map the platform services correctly
        final List<Resource> toFetch = new ArrayList<Resource>();
        for (final Iterator<Entry<Resource, Resource>> it = systemResources.entrySet().iterator(); it.hasNext();) {
            final Entry<Resource, Resource> entry = it.next();
            final Resource systemResource = entry.getKey();
            final Resource parent = entry.getValue();
            final Collection<Resource> children = rtn.remove(systemResource);
            if (children != null && !children.isEmpty()) {
                it.remove();
                final Collection<Resource> collection = rtn.get(parent);
                if (collection != null) {
                    collection.addAll(children);
                }
            } else if (children != null && children == Collections.EMPTY_LIST) {
                toFetch.add(systemResource);
            }
        }
        final Map<Resource, Collection<Resource>> systemResourceChildren = resourceManager
                .findChildResources(toFetch, viewable, true);
        for (final Entry<Resource, Resource> entry : systemResources.entrySet()) {
            final Resource systemResource = entry.getKey();
            final Resource parent = entry.getValue();
            final Collection<Resource> children = systemResourceChildren.get(systemResource);
            final Collection<Resource> parentChildren = rtn.get(parent);
            if (parentChildren != null && children != null) {
                parentChildren.addAll(children);
            }
        }
        return rtn;
    }

    private List<Resource> getPlatformsFromResourceIds(Set<Integer> viewable) {
        return new Transformer<Integer, Resource>() {
            public Resource transform(Integer resourceId) {
                final Resource r = resourceManager.getResourceById(resourceId);
                if (r != null && !r.isInAsyncDeleteState()
                        && AuthzConstants.authzPlatform.equals(r.getResourceType().getId())) {
                    return r;
                }
                return null;
            }
        }.transform(viewable);
    }

    @Transactional(readOnly = true)
    public RegistrationID register(ApiMessageContext messageContext, ResourceDetailsType responseMetadata,
            ResourceFilterRequest resourceFilterRequest) throws PermissionException, NotFoundException {
        AuthzSubject authzSubject = messageContext.getAuthzSubject();
        this.permissionManager.checkIsSuperUser(authzSubject);
        List<Filter<InventoryNotification, ? extends FilteringCondition<?>>> userFilters = resourceMapper
                .toResourceFilters(resourceFilterRequest, responseMetadata);

        RegistrationID registrationID = new RegistrationID();
        final HttpEndpointDefinition httpEndpointDefinition = resourceFilterRequest.getHttpEndpointDef();
        final NotificationEndpoint endpoint = (httpEndpointDefinition == null)
                ? new DefaultEndpoint(registrationID.getId())
                : getHttpEndpoint(registrationID, httpEndpointDefinition);
        final Integer authzSubjectId = authzSubject.getId();
        notificationsTransfer.register(endpoint, ResourceDetailsType.valueOf(responseMetadata), authzSubjectId);
        evaluator.register(endpoint, userFilters);
        return registrationID;
    }

    public ExternalRegistrationStatus getRegistrationStatus(final ApiMessageContext messageContext,
            final String registrationID) throws PermissionException, NotFoundException, UnknownEndpointException {
        AuthzSubject authzSubject = messageContext.getAuthzSubject();
        this.permissionManager.checkIsSuperUser(authzSubject);
        FilterChain<InventoryNotification> filterChain = evaluator.getRegistration(registrationID);
        NotificationsTransferImpl.EndpointStatusAndDefinition endpointStatusAndDefinition = this.notificationsTransfer
                .getEndointStatus(registrationID);
        return new ExternalRegistrationStatus(endpointStatusAndDefinition.getEndpoint(), filterChain,
                registrationID, endpointStatusAndDefinition.getExternalEndpointStatus());
    }

    public void unregister(final ApiMessageContext messageContext, NotificationEndpoint endpoint)
            throws PermissionException {
        AuthzSubject authzSubject = messageContext.getAuthzSubject();
        this.permissionManager.checkIsSuperUser(authzSubject);
        evaluator.unregisterAll(endpoint);
    }

    public ResourceMapper getResourceMapper() {
        return this.resourceMapper;
    }

    public PlatformManager getPlatformManager() {
        return this.platformManager;
    }

    public ResourceManager getResourceManager() {
        return this.resourceManager;
    }

    public final AppdefBoss getAppdefBoss() {
        return this.appdepBoss;
    }//EOM 

    private HttpEndpoint getHttpEndpoint(RegistrationID registrationID, HttpEndpointDefinition def) {
        return new HttpEndpoint(registrationID.getId(), def.getUrl(), def.getUsername(), def.getPassword(),
                def.getContentType(), def.getEncoding(), def.getBodyPrepend());
    }
}//EOC