/* * 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.das.util; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.SortedMap; import java.util.TreeMap; import org.apache.felix.das.DriverAttributes; import org.apache.felix.das.Log; import org.osgi.framework.Bundle; import org.osgi.framework.ServiceReference; import org.osgi.service.device.Constants; import org.osgi.service.device.DriverSelector; import org.osgi.service.device.Match; /** * TODO: add javadoc * * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> */ public class DriverMatcher { private final Log m_log; SortedMap<Integer, List<DriverAttributes>> m_map = new TreeMap<Integer, List<DriverAttributes>>(); List<Match> m_matches = new ArrayList<Match>(); public DriverMatcher( Log log ) { m_log = log; } // we keep track of the driver attributes in two // lists, one to aid us if there is no driver selector, one // if there is... public void add( Integer match, DriverAttributes value ) { List<DriverAttributes> da = get( match ); da.add( value ); m_matches.add( new MatchImpl( value.getReference(), match ) ); } private List<DriverAttributes> get( Integer key ) { List<DriverAttributes> da = m_map.get( key ); if ( da == null ) { m_map.put( ( Integer ) key, new ArrayList<DriverAttributes>() ); } return m_map.get( key ); } public Match getBestMatch() { if ( m_map.isEmpty() ) { return null; } int matchValue = m_map.lastKey(); // these are the matches that // got the highest match value List<DriverAttributes> das = m_map.get( matchValue ); if ( das.size() == 1 ) { // a shortcut: there's only one with the highest match return new MatchImpl( das.get( 0 ).getReference(), matchValue ); } // get the highest ranking driver final SortedMap<ServiceReference, Match> matches = new TreeMap<ServiceReference, Match>( new ServicePriority() ); for ( DriverAttributes da : das ) { matches.put( da.getReference(), new MatchImpl( da.getReference(), matchValue ) ); } ServiceReference last = matches.lastKey(); return matches.get( last ); } public Match selectBestMatch( ServiceReference deviceRef, DriverSelector selector ) { // Match[] matches = m_matches.toArray( new Match[0] ); //(re)check bundle status List<Match> activeMatches = new ArrayList<Match>(); for (Match match : m_matches) { if (match.getDriver().getBundle().getState() == Bundle.ACTIVE) { activeMatches.add(match); } else { m_log.debug("skipping: " + match + ", it's bundle is: " + match.getDriver().getBundle().getState()); } } try { Match[] matches = activeMatches.toArray( new Match[0] ); int index = selector.select( deviceRef, matches ); if ( index != DriverSelector.SELECT_NONE && index >= 0 && index < matches.length ) { return matches[index]; } } catch ( Exception e ) { m_log.error( "exception thrown in DriverSelector.select()", e ); } return null; } private class MatchImpl implements Match { private final ServiceReference ref; private final int match; public MatchImpl( ServiceReference ref, int match ) { this.ref = ref; this.match = match; } public ServiceReference getDriver() { return ref; } public int getMatchValue() { return match; } public String toString() { return "[MatchImpl: DRIVER_ID=" + ref.getProperty( Constants.DRIVER_ID ) + ", match=" + match + "]"; } } private class ServicePriority implements Comparator<ServiceReference> { private int getValue( ServiceReference ref, String key, int defaultValue ) { Object obj = ref.getProperty( key ); if ( obj == null ) { return defaultValue; } try { return Integer.class.cast( obj ); } catch ( Exception e ) { return defaultValue; } } public int compare( ServiceReference o1, ServiceReference o2 ) { int serviceRanking1 = getValue( o1, org.osgi.framework.Constants.SERVICE_RANKING, 0 ); int serviceRanking2 = getValue( o2, org.osgi.framework.Constants.SERVICE_RANKING, 0 ); if ( serviceRanking1 != serviceRanking2 ) { return ( serviceRanking1 - serviceRanking2 ); } int serviceId1 = getValue( o1, org.osgi.framework.Constants.SERVICE_ID, Integer.MAX_VALUE ); int serviceId2 = getValue( o2, org.osgi.framework.Constants.SERVICE_ID, Integer.MAX_VALUE ); return ( serviceId2 - serviceId1 ); } } }