001package org.apache.commons.jcs.engine.control.event; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.IOException; 023import java.util.concurrent.LinkedBlockingQueue; 024import java.util.concurrent.ThreadPoolExecutor; 025import java.util.concurrent.TimeUnit; 026 027import org.apache.commons.jcs.engine.control.event.behavior.IElementEvent; 028import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler; 029import org.apache.commons.jcs.engine.control.event.behavior.IElementEventQueue; 030import org.apache.commons.jcs.utils.threadpool.DaemonThreadFactory; 031import org.apache.commons.logging.Log; 032import org.apache.commons.logging.LogFactory; 033 034/** 035 * An event queue is used to propagate ordered cache events to one and only one target listener. 036 */ 037public class ElementEventQueue 038 implements IElementEventQueue 039{ 040 private static final String THREAD_PREFIX = "JCS-ElementEventQueue-"; 041 042 /** The logger */ 043 private static final Log log = LogFactory.getLog( ElementEventQueue.class ); 044 045 /** shutdown or not */ 046 private boolean destroyed = false; 047 048 /** The event queue */ 049 private LinkedBlockingQueue<Runnable> queue; 050 051 /** The worker thread pool. */ 052 private ThreadPoolExecutor queueProcessor; 053 054 /** 055 * Constructor for the ElementEventQueue object 056 */ 057 public ElementEventQueue() 058 { 059 queue = new LinkedBlockingQueue<Runnable>(); 060 queueProcessor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, 061 queue, new DaemonThreadFactory(THREAD_PREFIX)); 062 063 if ( log.isDebugEnabled() ) 064 { 065 log.debug( "Constructed: " + this ); 066 } 067 } 068 069 /** 070 * Dispose queue 071 */ 072 @Override 073 public void dispose() 074 { 075 if ( !destroyed ) 076 { 077 destroyed = true; 078 079 // synchronize on queue so the thread will not wait forever, 080 // and then interrupt the QueueProcessor 081 queueProcessor.shutdownNow(); 082 queueProcessor = null; 083 084 if ( log.isInfoEnabled() ) 085 { 086 log.info( "Element event queue destroyed: " + this ); 087 } 088 } 089 } 090 091 /** 092 * Adds an ElementEvent to be handled 093 * @param hand The IElementEventHandler 094 * @param event The IElementEventHandler IElementEvent event 095 * @throws IOException 096 */ 097 @Override 098 public <T> void addElementEvent( IElementEventHandler hand, IElementEvent<T> event ) 099 throws IOException 100 { 101 102 if ( log.isDebugEnabled() ) 103 { 104 log.debug( "Adding Event Handler to QUEUE, !destroyed = " + !destroyed ); 105 } 106 107 if (destroyed) 108 { 109 log.warn("Event submitted to disposed element event queue " + event); 110 } 111 else 112 { 113 ElementEventRunner runner = new ElementEventRunner( hand, event ); 114 115 if ( log.isDebugEnabled() ) 116 { 117 log.debug( "runner = " + runner ); 118 } 119 120 queueProcessor.execute(runner); 121 } 122 } 123 124 // /////////////////////////// Inner classes ///////////////////////////// 125 126 /** 127 * Retries before declaring failure. 128 */ 129 protected abstract class AbstractElementEventRunner 130 implements Runnable 131 { 132 /** 133 * Main processing method for the AbstractElementEvent object 134 */ 135 @SuppressWarnings("synthetic-access") 136 @Override 137 public void run() 138 { 139 try 140 { 141 doRun(); 142 // happy and done. 143 } 144 catch ( IOException e ) 145 { 146 // Too bad. The handler has problems. 147 log.warn( "Giving up element event handling " + ElementEventQueue.this, e ); 148 } 149 } 150 151 /** 152 * This will do the work or trigger the work to be done. 153 * <p> 154 * @throws IOException 155 */ 156 protected abstract void doRun() 157 throws IOException; 158 } 159 160 /** 161 * ElementEventRunner. 162 */ 163 private class ElementEventRunner 164 extends AbstractElementEventRunner 165 { 166 /** the handler */ 167 private final IElementEventHandler hand; 168 169 /** event */ 170 private final IElementEvent<?> event; 171 172 /** 173 * Constructor for the PutEvent object. 174 * <p> 175 * @param hand 176 * @param event 177 * @throws IOException 178 */ 179 @SuppressWarnings("synthetic-access") 180 ElementEventRunner( IElementEventHandler hand, IElementEvent<?> event ) 181 throws IOException 182 { 183 if ( log.isDebugEnabled() ) 184 { 185 log.debug( "Constructing " + this ); 186 } 187 this.hand = hand; 188 this.event = event; 189 } 190 191 /** 192 * Tells the handler to handle the event. 193 * <p> 194 * @throws IOException 195 */ 196 @Override 197 protected void doRun() 198 throws IOException 199 { 200 hand.handleElementEvent( event ); 201 } 202 } 203}