📄 scanmanager.java
字号:
* Whether it's been cancelled by stop() **/ volatile boolean cancelled=false; /** * create a new SessionTask. **/ SessionTask(long scheduleNext) { delayBeforeNext = scheduleNext; taskid = taskcount++; } /** * When run() begins, the state is switched to RUNNING. * When run() ends then: * If the task is repeated, the state will be switched * to SCHEDULED (because a new task was scheduled). * Otherwise the state will be switched to either * STOPPED (if it was stopped before it could complete) * or COMPLETED (if it completed gracefully) * This method is used to switch to the desired state and * send the appropriate notifications. * When entering the method, we check whether the state is * STOPPED. If so, we return false - and the SessionTask will * stop. Otherwise, we switch the state to the desired value. **/ private boolean notifyStateChange(ScanState newState,String condition) { synchronized (ScanManager.this) { if (state == STOPPED || state == CLOSED) return false; switchState(newState,condition); } sendQueuedNotifications(); return true; } // Cancels this task. public boolean cancel() { cancelled=true; return super.cancel(); } /** * Invoke all directories scanners in sequence. At each * step, checks to see whether the task should stop. **/ private boolean execute() { final String tag = "Scheduled session["+taskid+"]"; try { if (cancelled) { LOG.finer(tag+" cancelled: done"); return false; } if (!notifyStateChange(RUNNING,"scan-running")) { LOG.finer(tag+" stopped: done"); return false; } scanAllDirectories(); } catch (Exception x) { if (LOG.isLoggable(Level.FINEST)) { LOG.log(Level.FINEST, tag+" failed to scan: "+x,x); } else if (LOG.isLoggable(Level.FINE)) { LOG.fine(tag+" failed to scan: "+x); } } return true; } /** * Schedule an identical task for next iteration. **/ private boolean scheduleNext() { final String tag = "Scheduled session["+taskid+"]"; // We need now to reschedule a new task for after 'delayBeforeNext' ms. try { LOG.finer(tag+": scheduling next session for "+ delayBeforeNext + "ms"); if (cancelled || !notifyStateChange(SCHEDULED,"scan-scheduled")) { LOG.finer(tag+" stopped: do not reschedule"); return false; } final SessionTask nextTask = new SessionTask(delayBeforeNext); if (!scheduleSession(nextTask,delayBeforeNext)) return false; LOG.finer(tag+": next session successfully scheduled"); } catch (Exception x) { if (LOG.isLoggable(Level.FINEST)) { LOG.log(Level.FINEST,tag+ " failed to schedule next session: "+x,x); } else if (LOG.isLoggable(Level.FINE)) { LOG.fine(tag+" failed to schedule next session: "+x); } } return true; } /** * The run method: * executes scanning logic, the schedule next iteration if needed. **/ public void run() { final String tag = "Scheduled session["+taskid+"]"; LOG.entering(SessionTask.class.getName(),"run"); LOG.finer(tag+" starting..."); try { if (execute()==false) return; LOG.finer(tag+" terminating - state is "+state+ ((delayBeforeNext >0)?(" next session is due in "+delayBeforeNext+" ms."): " no additional session scheduled")); // if delayBeforeNext <= 0 we are done, either because the session was // stopped or because it successfully completed. if (delayBeforeNext <= 0) { if (!notifyStateChange(COMPLETED,"scan-done")) LOG.finer(tag+" stopped: done"); else LOG.finer(tag+" completed: done"); return; } // we need to reschedule a new session for 'delayBeforeNext' ms. scheduleNext(); } finally { tasklist.remove(this); LOG.finer(tag+" finished..."); LOG.exiting(SessionTask.class.getName(),"run"); } } } // --------------------------------------------------------------- // --------------------------------------------------------------- // --------------------------------------------------------------- // MBean Notification support // The methods below are imported from {@link NotificationEmitter} // --------------------------------------------------------------- /** * Delegates the implementation of this method to the wrapped * {@code NotificationBroadcasterSupport} object. **/ public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException { broadcaster.addNotificationListener(listener, filter, handback); } /** * We emit an {@code AttributeChangeNotification} when the {@code State} * attribute changes. **/ public MBeanNotificationInfo[] getNotificationInfo() { return new MBeanNotificationInfo[] { new MBeanNotificationInfo(new String[] { AttributeChangeNotification.ATTRIBUTE_CHANGE}, AttributeChangeNotification.class.getName(), "Emitted when the State attribute changes") }; } /** * Delegates the implementation of this method to the wrapped * {@code NotificationBroadcasterSupport} object. **/ public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { broadcaster.removeNotificationListener(listener); } /** * Delegates the implementation of this method to the wrapped * {@code NotificationBroadcasterSupport} object. **/ public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException { broadcaster.removeNotificationListener(listener, filter, handback); } /** * Returns and increment the sequence number used for * notifications. We use the same sequence number throughout the * application - this is why this method is only package protected. * @return A unique sequence number for the next notification. */ static synchronized long getNextSeqNumber() { return seqNumber++; } // --------------------------------------------------------------- // End of MBean Notification support // --------------------------------------------------------------- // --------------------------------------------------------------- // MBeanRegistration support // The methods below are imported from {@link MBeanRegistration} // --------------------------------------------------------------- /** * Allows the MBean to perform any operations it needs before being * registered in the MBean server. If the name of the MBean is not * specified, the MBean can provide a name for its registration. If * any exception is raised, the MBean will not be registered in the * MBean server. * <p>In this implementation, we check that the provided name is * either {@code null} or equals to {@link #SCAN_MANAGER_NAME}. If it * isn't then we throw an IllegalArgumentException, otherwise we return * {@link #SCAN_MANAGER_NAME}.</p> * <p>This ensures that there will be a single instance of ScanManager * registered in a given MBeanServer, and that it will always be * registered with the singleton's {@link #SCAN_MANAGER_NAME}.</p> * <p>We do not need to check whether an MBean by that name is * already registered because the MBeanServer will perform * this check just after having called preRegister().</p> * @param server The MBean server in which the MBean will be registered. * @param name The object name of the MBean. This name is null if the * name parameter to one of the createMBean or registerMBean methods in * the MBeanServer interface is null. In that case, this method must * return a non-null ObjectName for the new MBean. * @return The name under which the MBean is to be registered. This value * must not be null. If the name parameter is not null, it will usually * but not necessarily be the returned value. * @throws Exception This exception will be caught by the MBean server and * re-thrown as an MBeanRegistrationException. */ public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { if (name != null) { if (!SCAN_MANAGER_NAME.equals(name)) throw new IllegalArgumentException(String.valueOf(name)); } mbeanServer = server; return SCAN_MANAGER_NAME; } // Returns the default configuration filename static String getDefaultConfigurationFileName() { // This is a file calles 'jmx-scandir.xml' located // in the user directory. final String user = System.getProperty("user.home"); final String defconf = user+File.separator+"jmx-scandir.xml"; return defconf; } /** * Allows the MBean to perform any operations needed after having * been registered in the MBean server or after the registration has * failed. * <p> * If registration was not successful, the method returns immediately. * <p> * If registration is successful, register the {@link ResultLogManager} * and default {@link ScanDirConfigMXBean}. If registering these * MBean fails, the {@code ScanManager} state will be switched to * {@link #close CLOSED}, and postRegister ends there. * </p> * <p>Otherwise the {@code ScanManager} will ask the * {@link ScanDirConfigMXBean} to load its configuration. * If it succeeds, the configuration will be {@link * #applyConfiguration applied}. Otherwise, the method simply returns, * assuming that the user will later create/update a configuration and * apply it. * @param registrationDone Indicates whether or not the MBean has been * successfully registered in the MBean server. The value false means * that the registration has failed. */ public void postRegister(Boolean registrationDone) { if (!registrationDone) return; Exception test=null; try { mbeanServer.registerMBean(log, ResultLogManager.RESULT_LOG_MANAGER_NAME); final String defconf = getDefaultConfigurationFileName(); final String conf = System.getProperty("scandir.config.file",defconf); final String confname = ScanDirConfig.guessConfigName(conf,defconf); final ObjectName defaultProfileName = makeMBeanName(ScanDirConfigMXBean.class,confname); if (!mbeanServer.isRegistered(defaultProfileName)) mbeanServer.registerMBean(new ScanDirConfig(conf), defaultProfileName); config = JMX.newMXBeanProxy(mbeanServer,defaultProfileName, ScanDirConfigMXBean.class,true); configmap.put(defaultProfileName,config); } catch (Exception x) { LOG.config("Failed to populate MBeanServer: "+x); close(); return; } try { config.load(); } catch (Exception x) { LOG.finest("No config to load: "+x); test = x; } if (test == null) { try { applyConfiguration(config.getConfiguration()); } catch (Exception x) { if (LOG.isLoggable(Level.FINEST)) LOG.log(Level.FINEST,"Failed to apply config: "+x,x); LOG.config("Failed to apply config: "+x); } } } // Unregisters all created DirectoryScanners private void unregisterScanners() throws JMException { unregisterMBeans(scanmap); } // Unregisters all created ScanDirConfigs private void unregisterConfigs() throws JMException { unregisterMBeans(configmap); } // Unregisters all MBeans named by the given map private void unregisterMBeans(Map<ObjectName,?> map) throws JMException { for (ObjectName key : map.keySet()) { if (mbeanServer.isRegistered(key)) mbeanServer.unregisterMBean(key); map.remove(key); } } // Unregisters the ResultLogManager. private void unregisterResultLogManager() throws JMException { final ObjectName name = ResultLogManager.RESULT_LOG_MANAGER_NAME; if (mbeanServer.isRegistered(name)) { mbeanServer.unregisterMBean(name); } } /** * Allows the MBean to perform any operations it needs before being * unregistered by the MBean server. * This implementation also unregisters all the MXBeans * that were created by this object. * @throws IllegalStateException if the lock can't be acquire, or if * the MBean's state doesn't allow the MBean to be unregistered * (e.g. because it's scheduled or running). * @throws Exception This exception will be caught by the MBean server and * re-thrown as an MBeanRegistrationException. */ public void preDeregister() throws Exception { try { close(); if (!sequencer.tryAcquire()) throw new IllegalStateException("can't acquire lock"); try { unregisterScanners(); unregisterConfigs(); unregisterResultLogManager(); } finally { sequencer.release(); } } catch (Exception x) { LOG.log(Level.FINEST,"Failed to unregister: "+x,x); throw x; } } /** * Allows the MBean to perform any operations needed after having been * unregistered in the MBean server. * Cancels the internal timer - if any. */ public synchronized void postDeregister() { if (timer != null) { try { timer.cancel(); } catch (Exception x) { if (LOG.isLoggable(Level.FINEST)) LOG.log(Level.FINEST,"Failed to cancel timer",x); else if (LOG.isLoggable(Level.FINE)) LOG.fine("Failed to cancel timer: "+x); } finally { timer = null; } } } // --------------------------------------------------------------- // End of MBeanRegistration support // ---------------------------------------------------------------}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -