/* * 2012-3 Red Hat Inc. and/or its affiliates and other contributors. * * 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.overlord.rtgov.activity.collector.activity.server; import java.text.MessageFormat; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import javax.management.ListenerNotFoundException; import javax.management.MBeanNotificationInfo; import javax.management.Notification; import javax.management.NotificationFilter; import javax.management.NotificationListener; import org.overlord.commons.services.ServiceClose; import org.overlord.commons.services.ServiceInit; import org.overlord.commons.services.ServiceRegistryUtil; import org.overlord.rtgov.activity.model.ActivityUnit; import org.overlord.rtgov.activity.server.ActivityServer; import org.overlord.rtgov.activity.collector.BatchedActivityUnitLogger; import org.overlord.rtgov.common.util.RTGovProperties; /** * This class provides a bridge between the Collector and Activity Server, * where activity events are logged, causing them to be sent to the * configured activity server. * */ public class ActivityServerLogger extends BatchedActivityUnitLogger implements ActivityServerLoggerMBean, javax.management.NotificationEmitter { private static final Logger LOG=Logger.getLogger(ActivityServerLogger.class.getName()); private static final int DURATION_BETWEEN_FAILURE_REPORTS = 5 * 60 * 1000; private static final int MAX_THREADS = 10; private static final int FREE_ACTIVITY_LIST_QUEUE_SIZE = 100; private static final int ACTIVITY_LIST_QUEUE_SIZE = 10000; private Integer _durationBetweenFailureReports=DURATION_BETWEEN_FAILURE_REPORTS; private Integer _maxThreads=MAX_THREADS; private Integer _freeActivityListQueueSize=FREE_ACTIVITY_LIST_QUEUE_SIZE; private Integer _activityListQueueSize=ACTIVITY_LIST_QUEUE_SIZE; private java.util.concurrent.BlockingQueue<java.util.List<ActivityUnit>> _queue=null; private java.util.concurrent.BlockingQueue<java.util.List<ActivityUnit>> _freeActivityLists=null; private ActivityServer _activityServer=null; private java.util.List<ActivityUnit> _activities=null; private java.util.Set<Thread> _threads=new java.util.HashSet<Thread>(); private java.util.List<NotificationDetails> _notificationDetails= new java.util.ArrayList<NotificationDetails>(); private int _sequenceNumber=1; private long _lastFailure=0; private int _failuresSinceLastSuccess=0; /** * This method initializes the Activity Server Logger. */ @ServiceInit public void init() { // Obtain the Activity Server if (_activityServer == null) { _activityServer = ServiceRegistryUtil.getSingleService(ActivityServer.class); } if (LOG.isLoggable(Level.FINE)) { LOG.fine("Initialize Logger for Activity Server (max threads "+_maxThreads+"): "+_activityServer); } _maxThreads = RTGovProperties.getPropertyAsInteger("ActivityServerLogger.maxThreads", MAX_THREADS); _durationBetweenFailureReports = RTGovProperties.getPropertyAsInteger("ActivityServerLogger.durationBetweenFailureReports", DURATION_BETWEEN_FAILURE_REPORTS); _freeActivityListQueueSize = RTGovProperties.getPropertyAsInteger("ActivityServerLogger.freeActivityListQueueSize", FREE_ACTIVITY_LIST_QUEUE_SIZE); _activityListQueueSize = RTGovProperties.getPropertyAsInteger("ActivityServerLogger.activityListQueueSize", ACTIVITY_LIST_QUEUE_SIZE); _queue=new java.util.concurrent.ArrayBlockingQueue<java.util.List<ActivityUnit>>(_activityListQueueSize); _freeActivityLists=new java.util.concurrent.ArrayBlockingQueue<java.util.List<ActivityUnit>>(_freeActivityListQueueSize); // Start dispatch thread for (int i=0; i < _maxThreads; i++) { Thread thread = new Thread(new Runnable() { public void run() { while (true) { try { java.util.List<ActivityUnit> list=_queue.take(); _activityServer.store(list); // Free up the list list.clear(); // Add protection to make sure list cannot grow unnecessarily large if (_freeActivityLists.size() < _maxThreads * 2) { _freeActivityLists.offer(list); } _failuresSinceLastSuccess = 0; } catch (Exception e) { reportFailure(e); } } } }); _threads.add(thread); thread.setDaemon(true); thread.start(); } super.init(); } /** * This method handles reporting failures. * * @param e The exception */ protected void reportFailure(Exception e) { _failuresSinceLastSuccess++; long currentTime=System.currentTimeMillis(); if (currentTime > _lastFailure + _durationBetweenFailureReports) { LOG.log(Level.SEVERE, "Failed to store list of activity units", e); _lastFailure = currentTime; Notification notification=new Notification(java.util.PropertyResourceBundle.getBundle( "collector-activity-server.Messages").getString("COLLECTOR-ACTIVITY-SERVER-1"), this, _sequenceNumber++, MessageFormat.format( java.util.PropertyResourceBundle.getBundle( "collector-activity-server.Messages").getString("COLLECTOR-ACTIVITY-SERVER-2"), e.getMessage())); for (NotificationDetails n : _notificationDetails) { n.getListener().handleNotification(notification, n.getHandback()); } } } /** * {@inheritDoc} */ public int getFailuresSinceLastSuccess() { return (_failuresSinceLastSuccess); } /** * This method sets the activity server. * * @param activityServer The activity server */ public void setActivityServer(ActivityServer activityServer) { _activityServer = activityServer; } /** * This method gets the activity server. * * @return The activity server */ public ActivityServer getActivityServer() { return (_activityServer); } /** * {@inheritDoc} */ public int getPendingActivityUnits() { return (_queue.size()); } /** * {@inheritDoc} */ protected void appendActivity(ActivityUnit act) throws Exception { if (_activities == null) { _activities = new java.util.ArrayList<ActivityUnit>(); } _activities.add(act); } /** * {@inheritDoc} */ protected void sendMessage() throws Exception { if (_activities != null) { if (!_queue.offer(_activities, 500, TimeUnit.MILLISECONDS)) { LOG.warning("Failed to send message - queue is full"); } // Clear the list _activities = _freeActivityLists.poll(); if (_activities == null) { _activities = new java.util.ArrayList<ActivityUnit>(); } } } /** * This method closes the Activity Server Logger. */ @ServiceClose public void close() { if (LOG.isLoggable(Level.FINE)) { LOG.fine("Close Logger for Activity Server"); } super.close(); } /** * {@inheritDoc} */ public void addNotificationListener(NotificationListener l, NotificationFilter filter, Object handback) throws IllegalArgumentException { _notificationDetails.add(new NotificationDetails(l, filter, handback)); } /** * {@inheritDoc} */ public MBeanNotificationInfo[] getNotificationInfo() { return new MBeanNotificationInfo[0]; } /** * {@inheritDoc} */ public void removeNotificationListener(NotificationListener l) throws ListenerNotFoundException { boolean f_found=false; for (int i=_notificationDetails.size()-1; i >= 0; i--) { NotificationDetails n=_notificationDetails.get(i); if (n.getListener() == l) { _notificationDetails.remove(i); f_found = true; } } if (!f_found) { throw new ListenerNotFoundException(); } } /** * {@inheritDoc} */ public void removeNotificationListener(NotificationListener l, NotificationFilter filter, Object handback) throws ListenerNotFoundException { boolean f_found=false; for (int i=_notificationDetails.size()-1; i >= 0; i--) { NotificationDetails n=_notificationDetails.get(i); if (n.getListener() == l && n.getFilter() == filter && n.getHandback() == handback) { _notificationDetails.remove(i); f_found = true; break; } } if (!f_found) { throw new ListenerNotFoundException(); } } /** * This class provides a container for the listener details. * */ protected class NotificationDetails { private NotificationListener _listener=null; private NotificationFilter _filter=null; private Object _handback=null; /** * This is the constructor. * * @param listener The listener * @param filter The filter * @param handback The handback */ public NotificationDetails(NotificationListener listener, NotificationFilter filter, Object handback) { _listener = listener; _filter = filter; _handback = handback; } /** * The listener. * * @return The listener */ public NotificationListener getListener() { return (_listener); } /** * The filter. * * @return The filter */ public NotificationFilter getFilter() { return (_filter); } /** * The handback. * * @return The handback */ public Object getHandback() { return (_handback); } } }