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 }