blob: f97c97492e6ba16d96c760141a9dd39432cfbac9 [file] [log] [blame]
/*
* 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 );
}
}
}