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    /**
48     * The type of instances created by this factory.
49     */
50    private final Class<T> type;
51  
52    // ****************************** Initializer *******************************
53  
54    // ****************************** Constructors ******************************
55  
56    /**
57     * Default constructor.
58     *
59     * @param type the type of instances created by this factory.
60     */
61    protected AbstractServiceFactory(final Class<T> type)
62    {
63      this.type = Arg.checkNotNull("type", type);
64    }
65  
66    // ****************************** Inner Classes *****************************
67  
68    // ********************************* Methods ********************************
69  
70    // --- init -----------------------------------------------------------------
71  
72    // --- get&set --------------------------------------------------------------
73  
74    // --- business -------------------------------------------------------------
75  
76    /**
77     * Creates an instance of a service in <code>META-INF/services</code>.
78     *
79     * @return instance of the desired type.
80     * @throws ResourceException if a type cannot be instantiated.
81     */
82    public final T create() throws ResourceException
83    {
84      return create(null);
85    }
86  
87    /**
88     * Creates an instance of a service in <code>META-INF/services</code>.
89     *
90     * @param defaultType the default type to use if there is no configuration
91     *          file found in <code>META-INF/services</code>.
92     * @return instance of the desired type.
93     * @throws ResourceException if a type cannot be instantiated.
94     */
95    public final T create(final Class<? extends T> defaultType) throws ResourceException
96    {
97      final Iterator<T> iterator = ServiceLoader.load(type).iterator();
98  
99      final TypeProblemMessageBean.Builder builder =
100         new TypeProblemMessageBean.Builder().with(type);
101 
102     T instance = fetchInstance(iterator, builder);
103 
104     if (instance == null)
105     {
106       if (builder.hasReportedProblems())
107       {
108         throw new ResourceException(builder.build());
109       }
110       else
111       {
112         instance = handleWithDefaultType(defaultType);
113       }
114     }
115     else
116     {
117       if (builder.hasReportedProblems())
118       {
119         LOG.warn(builder.toMessage());
120       }
121     }
122 
123     return instance;
124   }
125 
126   private T fetchInstance(final Iterator<T> iterator,
127       final TypeProblemMessageBean.Builder builder)
128   {
129     T instance = null;
130     while (iterator.hasNext())
131     {
132       try
133       {
134         if (instance != null)
135         {
136           final String implementation = iterator.next().getClass().getName();
137           builder.withDuplicate(implementation);
138           continue;
139         }
140 
141         instance = iterator.next();
142       }
143       catch (final ServiceConfigurationError e)
144       {
145         builder.withError(e.getMessage());
146       }
147     }
148     return instance;
149   }
150 
151   private T handleWithDefaultType(final Class<? extends T> defaultType)
152     throws ResourceException
153   {
154     if (defaultType != null)
155     {
156       try
157       {
158         final T instance = defaultType.newInstance();
159         return instance;
160       }
161       catch (final Exception e)
162       {
163         throw new ResourceException(new TypeProblemMessageBean(e, type));
164       }
165     }
166     else
167     {
168       throw new ResourceException(new TypeProblemMessageBean(type));
169     }
170   }
171 
172   // --- object basics --------------------------------------------------------
173 }