| /* |
| * 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.http.base.internal.registry; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.EventListener; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.NoSuchElementException; |
| |
| import org.jetbrains.annotations.NotNull; |
| |
| import org.apache.felix.http.base.internal.handler.ListenerHandler; |
| import org.apache.felix.http.base.internal.runtime.ListenerInfo; |
| import org.apache.felix.http.base.internal.runtime.dto.ListenerDTOBuilder; |
| import org.osgi.service.http.runtime.dto.FailedListenerDTO; |
| import org.osgi.service.http.runtime.dto.ListenerDTO; |
| |
| public class ListenerMap<T extends EventListener> { |
| |
| private volatile List<ListenerRegistrationStatus<T>> handlers = Collections.emptyList(); |
| |
| /** |
| * The status object keeps track of the registration status of a listener |
| * The status objects are sorted by result first, followed by ranking. The active |
| * listeners ( result == -1) are first, followed by the inactive ones. This sorting |
| * allows to only traverse over the active ones and also avoids any sorting |
| * as the listeners are processed in the correct order already. |
| */ |
| private static final class ListenerRegistrationStatus<T> implements Comparable<ListenerRegistrationStatus<T>> |
| { |
| private final int result; |
| private final ListenerHandler handler; |
| |
| public ListenerRegistrationStatus(@NotNull final ListenerHandler handler, final int result) |
| { |
| this.handler = handler; |
| this.result = result; |
| } |
| |
| public int getResult() |
| { |
| return this.result; |
| } |
| |
| public @NotNull ListenerHandler getHandler() |
| { |
| return this.handler; |
| } |
| |
| @Override |
| public int compareTo(final ListenerRegistrationStatus<T> o) |
| { |
| int result = this.result - o.result; |
| if ( result == 0 ) |
| { |
| result = this.handler.compareTo(o.handler); |
| } |
| return result; |
| } |
| } |
| |
| public synchronized void cleanup() |
| { |
| this.handlers = Collections.emptyList(); |
| } |
| |
| public synchronized void add(final ListenerHandler handler, final int reason) |
| { |
| final ListenerRegistrationStatus<T> status = new ListenerRegistrationStatus<T>(handler, reason); |
| |
| final List<ListenerRegistrationStatus<T>> newList = new ArrayList<ListenerMap.ListenerRegistrationStatus<T>>(this.handlers); |
| newList.add(status); |
| Collections.sort(newList); |
| this.handlers = newList; |
| } |
| |
| public synchronized ListenerHandler remove(final ListenerInfo info) |
| { |
| final List<ListenerRegistrationStatus<T>> newList = new ArrayList<ListenerMap.ListenerRegistrationStatus<T>>(this.handlers); |
| final Iterator<ListenerRegistrationStatus<T>> i = newList.iterator(); |
| while ( i.hasNext() ) |
| { |
| final ListenerRegistrationStatus<T> status = i.next(); |
| if ( status.getHandler().getListenerInfo().equals(info) ) |
| { |
| i.remove(); |
| this.handlers = newList; |
| |
| return status.getResult() == -1 ? status.getHandler() : null; |
| } |
| } |
| return null; |
| } |
| |
| public ListenerHandler getListenerHandler(@NotNull final ListenerInfo info) |
| { |
| final List<ListenerRegistrationStatus<T>> list = this.handlers; |
| for(final ListenerRegistrationStatus<T> status : list) |
| { |
| if ( status.getHandler().getListenerInfo().equals(info) ) |
| { |
| return status.getHandler(); |
| } |
| } |
| return null; |
| } |
| |
| public Iterable<ListenerHandler> getActiveHandlers() |
| { |
| final List<ListenerRegistrationStatus<T>> list = this.handlers; |
| final Iterator<ListenerRegistrationStatus<T>> iter = list.iterator(); |
| final Iterator<ListenerHandler> newIter = new Iterator<ListenerHandler>() |
| { |
| |
| private ListenerHandler next; |
| |
| { |
| peek(); |
| } |
| |
| private void peek() |
| { |
| next = null; |
| if ( iter.hasNext() ) |
| { |
| final ListenerRegistrationStatus<T> status = iter.next(); |
| if ( status.getResult() == -1 ) |
| { |
| next = status.getHandler(); |
| } |
| } |
| } |
| |
| @Override |
| public boolean hasNext() |
| { |
| return this.next != null; |
| } |
| |
| @Override |
| public ListenerHandler next() |
| { |
| if ( this.next == null ) |
| { |
| throw new NoSuchElementException(); |
| } |
| final ListenerHandler result = this.next; |
| peek(); |
| return result; |
| } |
| |
| @Override |
| public void remove() |
| { |
| throw new UnsupportedOperationException(); |
| } |
| }; |
| return new Iterable<ListenerHandler>() |
| { |
| |
| @Override |
| public Iterator<ListenerHandler> iterator() |
| { |
| return newIter; |
| } |
| }; |
| } |
| |
| public Iterable<T> getActiveListeners() |
| { |
| final Iterator<ListenerHandler> iter = this.getActiveHandlers().iterator(); |
| final Iterator<T> newIter = new Iterator<T>() |
| { |
| |
| private T next; |
| |
| { |
| peek(); |
| } |
| |
| @SuppressWarnings("unchecked") |
| private void peek() |
| { |
| next = null; |
| while ( next == null && iter.hasNext() ) |
| { |
| final ListenerHandler handler = iter.next(); |
| next = (T)handler.getListener(); |
| } |
| } |
| |
| @Override |
| public boolean hasNext() |
| { |
| return this.next != null; |
| } |
| |
| @Override |
| public T next() |
| { |
| if ( this.next == null ) |
| { |
| throw new NoSuchElementException(); |
| } |
| final T result = this.next; |
| peek(); |
| return result; |
| } |
| |
| @Override |
| public void remove() |
| { |
| throw new UnsupportedOperationException(); |
| } |
| }; |
| return new Iterable<T>() |
| { |
| |
| @Override |
| public Iterator<T> iterator() |
| { |
| return newIter; |
| } |
| }; |
| } |
| |
| public void getRuntimeInfo(final List<ListenerDTO> listenerDTOs, final List<FailedListenerDTO> failedListenerDTOs) |
| { |
| final int length = listenerDTOs.size(); |
| final int failedLength = failedListenerDTOs.size(); |
| final List<ListenerRegistrationStatus<T>> list = this.handlers; |
| for (final ListenerRegistrationStatus<T> status : list) |
| { |
| // search for DTO with same service id and failureCode |
| if ( status.getResult() == -1 ) |
| { |
| int index = 0; |
| boolean found = false; |
| final Iterator<ListenerDTO> i = listenerDTOs.iterator(); |
| while ( !found && index < length ) |
| { |
| final ListenerDTO dto = i.next(); |
| if ( dto.serviceId == status.getHandler().getListenerInfo().getServiceId() ) |
| { |
| found = true; |
| } |
| index++; |
| } |
| if ( !found ) |
| { |
| listenerDTOs.add(ListenerDTOBuilder.build(status.getHandler(), status.getResult())); |
| } |
| } |
| else |
| { |
| int index = 0; |
| boolean found = false; |
| final Iterator<FailedListenerDTO> i = failedListenerDTOs.iterator(); |
| while ( !found && index < failedLength ) |
| { |
| final FailedListenerDTO dto = i.next(); |
| if ( dto.serviceId == status.getHandler().getListenerInfo().getServiceId() |
| && dto.failureReason == status.getResult() ) |
| { |
| found = true; |
| } |
| index++; |
| } |
| if ( !found ) |
| { |
| failedListenerDTOs.add((FailedListenerDTO)ListenerDTOBuilder.build(status.getHandler(), status.getResult())); |
| } |
| } |
| } |
| } |
| } |