View Javadoc

1   /*
2    * Copyright 2012-2013 smartics, Kronseder & Reiner GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package de.smartics.properties.resource.util;
17  
18  import java.util.Iterator;
19  import java.util.ServiceConfigurationError;
20  import java.util.ServiceLoader;
21  
22  import org.slf4j.Logger;
23  import org.slf4j.LoggerFactory;
24  
25  import de.smartics.properties.resource.domain.ResourceException;
26  import de.smartics.util.lang.Arg;
27  
28  /**
29   * A factory to create instances of a given type using the Java Service API.
30   *
31   * @param <T> the type of the service to instantiate.
32   */
33  public abstract class AbstractServiceFactory<T>
34  {
35    // ********************************* Fields *********************************
36  
37    // --- constants ------------------------------------------------------------
38  
39    /**
40     * Reference to the logger for this class.
41     */
42    private static final Logger LOG = LoggerFactory
43        .getLogger(AbstractServiceFactory.class);
44  
45    // --- members --------------------------------------------------------------
46  
47    private final InstanceCreator<T> creator;
48  
49    // ****************************** Initializer *******************************
50  
51    // ****************************** Constructors ******************************
52  
53    /**
54     * Default constructor.
55     *
56     * @param creator the creator of instances created as defaults by this
57     *          factory.
58     * @throws NullPointerException if {@code creator} is <code>null</code>.
59     */
60    protected AbstractServiceFactory(final InstanceCreator<T> creator)
61    {
62      this.creator = Arg.checkNotNull("creator", creator);
63    }
64  
65    // ****************************** Inner Classes *****************************
66  
67    // ********************************* Methods ********************************
68  
69    // --- init -----------------------------------------------------------------
70  
71    // --- get&set --------------------------------------------------------------
72  
73    // --- business -------------------------------------------------------------
74  
75    /**
76     * Creates an instance of a service in <code>META-INF/services</code>.
77     *
78     * @return instance of the desired type.
79     * @throws ResourceException if a type cannot be instantiated.
80     */
81    public final T create() throws ResourceException
82    {
83      return create(null);
84    }
85  
86    /**
87     * Creates an instance of a service in <code>META-INF/services</code>.
88     *
89     * @param defaultType the default type to use if there is no configuration
90     *          file found in <code>META-INF/services</code>.
91     * @return instance of the desired type.
92     * @throws ResourceException if a type cannot be instantiated.
93     */
94    public final T create(final Class<? extends T> defaultType)
95      throws ResourceException
96    {
97      final Class<T> type = creator.getType();
98      final Iterator<T> iterator = ServiceLoader.load(type).iterator();
99  
100     final TypeProblemMessageBean.Builder builder =
101         new TypeProblemMessageBean.Builder().with(type);
102 
103     T instance = fetchInstance(iterator, builder);
104 
105     if (instance == null)
106     {
107       if (builder.hasReportedProblems())
108       {
109         throw new ResourceException(builder.build());
110       }
111       else
112       {
113         instance = creator.create();
114         if (instance == null)
115         {
116           instance = handleWithDefaultType(defaultType);
117         }
118       }
119     }
120     else
121     {
122       if (builder.hasReportedProblems())
123       {
124         LOG.warn(builder.toMessage());
125       }
126     }
127 
128     return instance;
129   }
130 
131   private T fetchInstance(final Iterator<T> iterator,
132       final TypeProblemMessageBean.Builder builder)
133   {
134     T instance = null;
135     while (iterator.hasNext())
136     {
137       try
138       {
139         if (instance != null)
140         {
141           final String implementation = iterator.next().getClass().getName();
142           builder.withDuplicate(implementation);
143           continue;
144         }
145 
146         instance = iterator.next();
147       }
148       catch (final ServiceConfigurationError e)
149       {
150         builder.withError(e.getMessage());
151       }
152     }
153     return instance;
154   }
155 
156   private T handleWithDefaultType(final Class<? extends T> defaultType)
157     throws ResourceException
158   {
159     if (defaultType != null)
160     {
161       try
162       {
163         final T instance = defaultType.newInstance();
164         return instance;
165       }
166       catch (final Exception e)
167       {
168         throw new ResourceException(new TypeProblemMessageBean(e,
169             creator.getType()));
170       }
171     }
172     else
173     {
174       throw new ResourceException(new TypeProblemMessageBean(creator.getType()));
175     }
176   }
177 
178   // --- object basics --------------------------------------------------------
179 }