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 }