/******************************************************************************* * Copyright (c) 2012 GigaSpaces Technologies Ltd. All rights reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ package org.cloudifysource.usm; import groovy.lang.Closure; import groovy.lang.GString; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.logging.Level; import org.cloudifysource.dsl.internal.CloudifyConstants; import org.cloudifysource.dsl.internal.CloudifyConstants.USMState; import org.cloudifysource.usm.details.Details; import org.cloudifysource.usm.monitors.Monitor; import org.openspaces.pu.service.CustomServiceDetails; import org.openspaces.pu.service.CustomServiceMonitors; import org.openspaces.pu.service.ServiceDetails; import org.openspaces.pu.service.ServiceMonitors; /***************** * A synchronized wrapper to the monitors functionality. The last monitors * results are cached for a set time. Note: this class also contains the code to * create the service details. The code for services and details is very * similar, even though service details is called exactly once. * * * @author barakme * @since 2.2.0 * */ public class MonitorsCache { private final USMLifecycleBean lifecycleBean; private ServiceMonitors[] lastResult; private final UniversalServiceManagerBean usm; private final long cacheExpirationTimeout; private long cacheExpirationTime = 0; private final String serviceSubType = "USM"; private final String serviceDescription = "USM"; private final String serviceLongDescription = "USM"; public MonitorsCache(final UniversalServiceManagerBean usm, final USMLifecycleBean lifecycleBean, final long cacheExpirationTimeout) { this.usm = usm; this.cacheExpirationTimeout = cacheExpirationTimeout; this.lifecycleBean = lifecycleBean; } /*********** * Returns the monitors from the cache if the cache expiration time has not * been exceeded, or reads the new monitor values and caches them, returning * the result. * * @return the monitors. */ public synchronized ServiceMonitors[] getMonitors() { final long now = System.currentTimeMillis(); if (now >= cacheExpirationTime) { logger.fine("Reloading monitors at: " + now); this.lastResult = createMonitors(); this.cacheExpirationTime = now + cacheExpirationTimeout; } return this.lastResult; } private static final java.util.logging.Logger logger = java.util.logging.Logger .getLogger(MonitorsCache.class.getName()); private void removeNonSerializableObjectsFromMap(final Map<?, ?> map, final String mapName) { if (map == null || map.keySet().isEmpty()) { return; } final Iterator<?> entries = map.entrySet().iterator(); while (entries.hasNext()) { final Entry<?, ?> entry = (Entry<?, ?>) entries.next(); // a closure can not be serialized // TODO - write a unit test for this. if (entry.getValue() != null) { if (!(entry.getValue() instanceof java.io.Serializable) || entry.getValue() instanceof Closure<?>) { logger.info("Entry " + entry.getKey() + " with value: " + entry.getValue().toString() + " is not serializable and was not inserted to the " + mapName + " map"); entries.remove(); } } } } private ServiceMonitors[] createMonitors() { final CustomServiceMonitors csm = new CustomServiceMonitors( CloudifyConstants.USM_MONITORS_SERVICE_ID); final ServiceMonitors[] res = new ServiceMonitors[] { csm }; final USMState currentState = usm.getState(); // If the underlying service is not running if (currentState != USMState.RUNNING) { csm.getMonitors().put(CloudifyConstants.USM_MONITORS_STATE_ID, currentState.ordinal()); return res; } final Map<String, Object> map = csm.getMonitors(); // default monitors putDefaultMonitorsInMap(map); for (final Monitor monitor : lifecycleBean.getMonitors()) { try { logger.fine("Executing monitor: " + monitor); final Map<String, Number> monitorValues = monitor .getMonitorValues(usm, lifecycleBean.getConfiguration()); removeNonSerializableObjectsFromMap(monitorValues, "monitors"); // add monitor values to Monitors map map.putAll(monitorValues); } catch (final Exception e) { logger.log(Level.SEVERE, "Failed to execute a USM service monitor", e); } } if (logger.isLoggable(Level.FINE)) { logger.fine("Monitors are: " + Arrays.toString(res)); } return res; } private void putDefaultMonitorsInMap(final Map<String, Object> map) { map.put(CloudifyConstants.USM_MONITORS_CHILD_PROCESS_ID, usm.getChildProcessID()); final List<Long> serviceProcessIDs = usm.getServiceProcessesList(); if (serviceProcessIDs.size() > 0) { if (serviceProcessIDs.size() == 1) { map.put(CloudifyConstants.USM_MONITORS_ACTUAL_PROCESS_ID, serviceProcessIDs.get(0)); } else { map.put(CloudifyConstants.USM_MONITORS_ACTUAL_PROCESS_ID, serviceProcessIDs); } } map.put(CloudifyConstants.USM_MONITORS_STATE_ID, usm.getState() .ordinal()); } /************** * Creates the service details - executed once. * * @return the service details. */ public ServiceDetails[] getServicesDetails() { logger.fine("Executing getServiceDetails()"); @SuppressWarnings("deprecation") final CustomServiceDetails csd = new CustomServiceDetails( CloudifyConstants.USM_DETAILS_SERVICE_ID, CustomServiceDetails.SERVICE_TYPE, this.serviceSubType, this.serviceDescription, this.serviceLongDescription); final ServiceDetails[] res = new ServiceDetails[] { csd }; final Details[] alldetails = lifecycleBean.getDetails(); final Map<String, Object> result = csd.getAttributes(); for (final Details details : alldetails) { try { logger.fine("Executing details: " + details); final Map<String, Object> detailsValues = details.getDetails( usm, lifecycleBean.getConfiguration()); removeNonSerializableObjectsFromMap(detailsValues, "details"); result.putAll(detailsValues); } catch (final Exception e) { logger.log(Level.SEVERE, "Failed to execute service details", e); } } // convert GStrings handleGStringDetails(result); if (logger.isLoggable(Level.FINER)) { logger.finer("Details are: " + Arrays.toString(res)); } return res; } /********** * If a details is a GString, return its toString() instead. * * @param result */ private void handleGStringDetails(final Map<String, Object> result) { final Set<Entry<String, Object>> entries = result.entrySet(); for (final Entry<String, Object> entry : entries) { if ((entry.getValue() != null) && (entry.getValue() instanceof GString)) { entry.setValue(entry.getValue().toString()); } } } }