Java tutorial
/* * 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