# ServiceQualifier.java

    /*
     * Copyright (c) 2008, Rickard Öberg. All Rights Reserved.
     *
     * Licensed 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.qi4j.api.service.qualifier;

    import org.qi4j.api.service.ServiceReference;
    import org.qi4j.functional.Specification;

    /**
     * This class helps you select a particular service
     * from a list.
     * <p>
     * Provide a Selector which does the actual
     * selection from the list. A common case is to select
     * based on identity of the service, which you can do this way:
     * </p>
     *
     * <pre><code>
     * new ServiceQualifier&lt;MyService&gt;(services, ServiceQualifier.withId("someId"))
     * </code></pre>
     * <p>
     * Many selectors can be combined by using firstOf. Example:
     * </p>
     * <pre><code>
     * new ServiceQualifier&lt;MyService&gt;(services, firstOf(withTags("sometag"), firstActive(), first()))
     * </code></pre>
     * <p>
     * This will pick a service that has the tag "sometag", or if none is found take the first active one. If no
     * service is active, then the first service will be picked.
     * </p>
     */
    public abstract class ServiceQualifier
    {
        public static <T> T firstService( Specification<ServiceReference<?>> qualifier,
                                          Iterable<ServiceReference<T>> services
        )
        {
            for( ServiceReference<T> service : services )
            {
                if( qualifier.satisfiedBy( service ) )
                {
                    return service.get();
                }
            }
            return null;
        }

        public static Specification<ServiceReference<?>> withId( final String anId )
        {
            return new Specification<ServiceReference<?>>()
            {
                @Override
                public boolean satisfiedBy( ServiceReference<?> service )
                {
                    return service.identity().equals( anId );
                }
            };
        }

        public static Specification<ServiceReference<?>> whereMetaInfoIs( final Object metaInfo )
        {
            return new Specification<ServiceReference<?>>()
            {
                @Override
                public boolean satisfiedBy( ServiceReference<?> service )
                {
                    Object metaObject = service.metaInfo( metaInfo.getClass() );
                    return metaObject != null && metaInfo.equals( metaObject );
                }
            };
        }

        public static Specification<ServiceReference<?>> whereActive()
        {
            return new Specification<ServiceReference<?>>()
            {
                @Override
                public boolean satisfiedBy( ServiceReference<?> service )
                {
                    return service.isActive();
                }
            };
        }

        public static Specification<ServiceReference<?>> whereAvailable()
        {
            return new Specification<ServiceReference<?>>()
            {
                @Override
                public boolean satisfiedBy( ServiceReference<?> service )
                {
                    return service.isAvailable();
                }
            };
        }

        public static Specification<ServiceReference<?>> withTags( final String... tags )
        {
            return new Specification<ServiceReference<?>>()
            {
                @Override
                public boolean satisfiedBy( ServiceReference<?> service )
                {
                    ServiceTags serviceTags = service.metaInfo( ServiceTags.class );

                    return serviceTags != null && serviceTags.hasTags( tags );
                }
            };
        }
    }