001    /*
002     * Copyright (c) 2007-2015 Concurrent, Inc. All Rights Reserved.
003     *
004     * Project and contact information: http://www.cascading.org/
005     *
006     * This file is part of the Cascading project.
007     *
008     * Licensed under the Apache License, Version 2.0 (the "License");
009     * you may not use this file except in compliance with the License.
010     * You may obtain a copy of the License at
011     *
012     *     http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing, software
015     * distributed under the License is distributed on an "AS IS" BASIS,
016     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017     * See the License for the specific language governing permissions and
018     * limitations under the License.
019     */
020    
021    package cascading.provider;
022    
023    import java.net.URL;
024    
025    import org.slf4j.Logger;
026    import org.slf4j.LoggerFactory;
027    
028    /**
029     * Class ProviderLoader is the base class for loading various "provider" types.
030     * <p/>
031     * This loader can optinally load a provider implementation within its own ClassLoader using the
032     * {@link ChildFirstURLClassLoader}.
033     *
034     * @see FactoryLoader
035     * @see ServiceLoader
036     */
037    public class ProviderLoader<Provider>
038      {
039      private static final Logger LOG = LoggerFactory.getLogger( ServiceLoader.class );
040      URL libraryURL;
041      String[] exclusions;
042    
043      ClassLoader classLoader;
044    
045      public ProviderLoader()
046        {
047        }
048    
049      public ProviderLoader( String[] exclusions, URL libraryURL )
050        {
051        this.exclusions = exclusions;
052        this.libraryURL = libraryURL;
053        }
054    
055      public Provider createProvider( String className )
056        {
057        // test for ant style token escapes
058        if( className == null || className.isEmpty() )
059          return null;
060    
061        if( className.startsWith( "@" ) && className.endsWith( "@" ) )
062          {
063          LOG.warn( "invalid classname: {}", className );
064          return null;
065          }
066    
067        try
068          {
069          Class<Provider> type = (Class<Provider>) getClassLoader().loadClass( className );
070    
071          return type.newInstance();
072          }
073        catch( ClassNotFoundException exception )
074          {
075          LOG.error( "unable to find service class: {}, with exception: {}", className, exception );
076          }
077        catch( IllegalAccessException exception )
078          {
079          LOG.error( "unable to instantiate service class: {}, with exception: {}", className, exception );
080          }
081        catch( InstantiationException exception )
082          {
083          LOG.error( "unable to instantiate service class: {}, with exception: {}", className, exception );
084          }
085    
086        return null;
087        }
088    
089      private synchronized ClassLoader getClassLoader()
090        {
091        if( classLoader != null )
092          return classLoader;
093    
094        if( libraryURL == null )
095          {
096          classLoader = Thread.currentThread().getContextClassLoader();
097          }
098        else
099          {
100          LOG.info( "loading services from library: {}", libraryURL );
101    
102          classLoader = new ChildFirstURLClassLoader( exclusions, libraryURL );
103          }
104    
105        return classLoader;
106        }
107      }