| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.felix.scr.impl.manager; |
| |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.TimeUnit; |
| |
| import org.osgi.service.log.LogService; |
| |
| /** |
| * EdgeInfo holds information about the service event tracking counts for creating (open) and disposing (close) |
| * implementation object instances per dependency manager. These need to be maintained for each implementation object instance |
| * because each instance (for a service factory) will have different sets of service references available. These need to be |
| * maintained for each dependency manager because the open/close tracking counts are obtained when the set of current |
| * service references is obtained, using a lock internal to the service tracker. |
| * |
| * |
| * The information in the open/close counts is used in the outOfRange method which determines if a service event tracking count |
| * occurred before the "open" event (in which case it is reflected in the open set already and does not need to be processed separately) |
| * or after the "close" event (in which case it is reflected in the close set already). |
| * |
| * The open latch is used to make sure that elements in the open set are completely processed before updated or unbind events |
| * are processed |
| * The close latch is used to make sure that unbind events that are out of range wait for the close to complete before returning; |
| * in this case the unbind is happening in the "close" thread rather than the service event thread, so we wait for the close to complete |
| * so that when the service event returns the unbind will actually have been completed. |
| * |
| * Related to this functionality is the missing tracking in AbstractComponentManager. This is used on close of an instance to make |
| * sure all service events occuring before close starts complete processing before the close takes action. |
| * |
| */ |
| |
| class EdgeInfo |
| { |
| private int open = -1; |
| private int close = -1; |
| private final CountDownLatch openLatch = new CountDownLatch(1); |
| private final CountDownLatch closeLatch = new CountDownLatch(1); |
| |
| public void setClose( int close ) |
| { |
| this.close = close; |
| } |
| |
| public CountDownLatch getOpenLatch() |
| { |
| return openLatch; |
| } |
| |
| public void waitForOpen(AbstractComponentManager<?> m_componentManager, String componentName, String methodName) |
| { |
| |
| CountDownLatch latch = getOpenLatch(); |
| String latchName = "open"; |
| waitForLatch( m_componentManager, latch, componentName, methodName, latchName ); |
| } |
| |
| public void waitForClose(AbstractComponentManager<?> m_componentManager, String componentName, String methodName) |
| { |
| |
| CountDownLatch latch = getCloseLatch(); |
| String latchName = "close"; |
| waitForLatch( m_componentManager, latch, componentName, methodName, latchName ); |
| } |
| |
| private void waitForLatch(AbstractComponentManager<?> m_componentManager, CountDownLatch latch, String componentName, |
| String methodName, String latchName) |
| { |
| try |
| { |
| if (!latch.await( m_componentManager.getLockTimeout(), TimeUnit.MILLISECONDS )) |
| { |
| m_componentManager.getLogger().log( LogService.LOG_ERROR, |
| "DependencyManager : {0} : timeout on {1} latch {2}", null, methodName, latchName, componentName ); |
| m_componentManager.dumpThreads(); |
| } |
| } |
| catch ( InterruptedException e ) |
| { |
| try |
| { |
| if (!latch.await( m_componentManager.getLockTimeout(), TimeUnit.MILLISECONDS )) |
| { |
| m_componentManager.getLogger().log( LogService.LOG_ERROR, |
| "DependencyManager : {0} : timeout on {1} latch {2}", null, methodName, latchName, componentName ); |
| m_componentManager.dumpThreads(); |
| } |
| } |
| catch ( InterruptedException e1 ) |
| { |
| m_componentManager.getLogger().log( LogService.LOG_ERROR, |
| "DependencyManager : {0} : Interrupted twice on {1} latch {2}", |
| null, methodName, latchName, componentName ); |
| Thread.currentThread().interrupt(); |
| } |
| Thread.currentThread().interrupt(); |
| } |
| } |
| |
| public CountDownLatch getCloseLatch() |
| { |
| return closeLatch; |
| } |
| |
| public void setOpen( int open ) |
| { |
| this.open = open; |
| } |
| |
| public void ignore() |
| { |
| open = Integer.MAX_VALUE; |
| close = Integer.MAX_VALUE - 1; |
| openLatch.countDown(); |
| closeLatch.countDown(); |
| } |
| |
| /** |
| * Returns whether the tracking count is before the open count or after the close count (if set) |
| * This must be called from within a block synchronized on m_tracker.tracked(). |
| * Setting open occurs in a synchronized block as well, to the tracker's current tracking count. |
| * Therefore if this outOfRange call finds open == -1 then open will be set to a tracking count |
| * at least as high as the argument tracking count. |
| * @param trackingCount tracking count from tracker to compare with range |
| * @return true if open not set, tracking count before open, or close set and tracking count after close. |
| */ |
| public boolean outOfRange( int trackingCount ) |
| { |
| return open == -1 |
| || trackingCount < open |
| || (close != -1 && trackingCount > close); |
| } |
| |
| public boolean beforeRange( int trackingCount ) |
| { |
| return open == -1 || trackingCount < open; |
| } |
| |
| public boolean afterRange( int trackingCount ) |
| { |
| return close != -1 && trackingCount > close; |
| } |
| } |