Skip to content

Commit f1ddfbd

Browse files
authored
Merge pull request #111 from yumaoka/rfe-110-Factory-CL
ResourceFilterFactory with a specified class loader
2 parents 787c1d8 + f3b96c2 commit f1ddfbd

2 files changed

Lines changed: 153 additions & 16 deletions

File tree

gp-res-filter/src/main/java/com/ibm/g11n/pipeline/resfilter/ResourceFilterFactory.java

Lines changed: 112 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,18 @@ private static class ResourceFilterRegistryEntry {
4343
}
4444
}
4545

46-
private static final Map<String, ResourceFilterRegistryEntry> REGISTRY = new HashMap<>();
46+
private Map<String, ResourceFilterRegistryEntry> registry;
4747

48-
static {
48+
private ResourceFilterFactory(ClassLoader cl) {
49+
Map<String, ResourceFilterRegistryEntry> map = new HashMap<>();
4950
// Walk through available provider implementations
50-
for (ResourceFilterProvider provider : ServiceLoader.load(ResourceFilterProvider.class)) {
51+
for (ResourceFilterProvider provider : ServiceLoader.load(ResourceFilterProvider.class, cl)) {
5152
Iterator<FilterInfo> filtItr = provider.getAvailableResourceFilters();
5253
while (filtItr.hasNext()) {
5354
FilterInfo filtInfo = filtItr.next();
5455
String id = filtInfo.getId().toUpperCase(Locale.ROOT);
55-
if (!REGISTRY.containsKey(id)) {
56-
REGISTRY.put(id, new ResourceFilterRegistryEntry(filtInfo, provider));
56+
if (!map.containsKey(id)) {
57+
map.put(id, new ResourceFilterRegistryEntry(filtInfo, provider));
5758
}
5859
}
5960
}
@@ -63,18 +64,50 @@ private static class ResourceFilterRegistryEntry {
6364
while (filtItr.hasNext()) {
6465
FilterInfo filtInfo = filtItr.next();
6566
String id = filtInfo.getId().toUpperCase(Locale.ROOT);
66-
if (!REGISTRY.containsKey(id)) {
67-
REGISTRY.put(id, new ResourceFilterRegistryEntry(filtInfo, defaultProvider));
67+
if (!map.containsKey(id)) {
68+
map.put(id, new ResourceFilterRegistryEntry(filtInfo, defaultProvider));
6869
}
6970
}
71+
registry = Collections.unmodifiableMap(map);
72+
}
73+
74+
private static volatile ResourceFilterFactory DEFAULT_FACTORY = null;
75+
76+
/**
77+
* Returns the default <code>ResourceFilterFactory</code> instance initialized
78+
* by the current thread's context class loader.
79+
*
80+
* @return The default <code>ResourceFilterFactory</code> instance.
81+
*/
82+
public static ResourceFilterFactory getDefaultInstance() {
83+
if (DEFAULT_FACTORY == null) {
84+
synchronized(ResourceFilterFactory.class) {
85+
if (DEFAULT_FACTORY == null) {
86+
DEFAULT_FACTORY = new ResourceFilterFactory(Thread.currentThread().getContextClassLoader());
87+
}
88+
}
89+
}
90+
return DEFAULT_FACTORY;
91+
}
92+
93+
/**
94+
* Returns an instance of <code>ResourceFilterFactory</code> using the specified
95+
* <code>ClassLoader</code> to look up custom {@link ResourceFilterProvider} implementations.
96+
*
97+
* @param cl The <code>ClassLoader</code> used for looking up custom <code>ResourceFilterProvider</code>
98+
* implementations.
99+
* @return A new instance of <code>ResourceFilterFactory</code>.
100+
*/
101+
public static ResourceFilterFactory getInstance(ClassLoader cl) {
102+
return new ResourceFilterFactory(cl);
70103
}
71104

72105
/**
73106
* Returns an unmodifiable view of the set of all available resource filter IDs.
74107
* @return an unmodifiable view of the set of all available resource filter IDs.
75108
*/
76-
public static Set<String> getAvailableFilterIds() {
77-
return Collections.unmodifiableSet(REGISTRY.keySet());
109+
public Set<String> availableFilterIds() {
110+
return Collections.unmodifiableSet(registry.keySet());
78111
}
79112

80113
/**
@@ -86,8 +119,8 @@ public static Set<String> getAvailableFilterIds() {
86119
* @return the resource filter information for the specified <code>filterId</code>,
87120
* or <code>null</code> if no matching filter is found.
88121
*/
89-
public static FilterInfo getFilterInfo(String filterId) {
90-
ResourceFilterRegistryEntry entry = REGISTRY.get(filterId.toUpperCase(Locale.ROOT));
122+
public FilterInfo filterInfo(String filterId) {
123+
ResourceFilterRegistryEntry entry = registry.get(filterId.toUpperCase(Locale.ROOT));
91124
if (entry == null) {
92125
return null;
93126
}
@@ -103,8 +136,8 @@ public static FilterInfo getFilterInfo(String filterId) {
103136
* @return an instance of {@link ResourceFilter} for the specified <code>filterId</code>,
104137
* or <code>null</code> if no matching filter is found.
105138
*/
106-
public static ResourceFilter getResourceFilter(String filterId) {
107-
ResourceFilterRegistryEntry entry = REGISTRY.get(filterId.toUpperCase(Locale.ROOT));
139+
public ResourceFilter resourceFilter(String filterId) {
140+
ResourceFilterRegistryEntry entry = registry.get(filterId.toUpperCase(Locale.ROOT));
108141
if (entry == null || entry.filterInfo.getType() != Type.SINGLE) {
109142
return null;
110143
}
@@ -120,11 +153,75 @@ public static ResourceFilter getResourceFilter(String filterId) {
120153
* @return an instance of {@link MultiBundleResourceFilter} for the specified <code>filterId</code>,
121154
* or <code>null</code> if no matching filter is found.
122155
*/
123-
public static MultiBundleResourceFilter getMultiBundleResourceFilter(String filterId) {
124-
ResourceFilterRegistryEntry entry = REGISTRY.get(filterId.toUpperCase(Locale.ROOT));
156+
public MultiBundleResourceFilter multiBundleResourceFilter(String filterId) {
157+
ResourceFilterRegistryEntry entry = registry.get(filterId.toUpperCase(Locale.ROOT));
125158
if (entry == null || entry.filterInfo.getType() != Type.MULTI) {
126159
return null;
127160
}
128161
return entry.provider.getMultiBundleResourceFilter(entry.filterInfo.getId());
129162
}
163+
164+
//
165+
// Following static methods were introduced in the initial implementation. These methods are
166+
// preserved for backward compatibility support.
167+
//
168+
169+
/**
170+
* Returns an unmodifiable view of the set of all available resource filter IDs by
171+
* the default factory.
172+
* <p>
173+
* This operation is equivalent to <code>getDefaultInstance().availableFilterIds()</code>.
174+
* @return an unmodifiable view of the set of all available resource filter IDs.
175+
*/
176+
public static Set<String> getAvailableFilterIds() {
177+
return getDefaultInstance().availableFilterIds();
178+
}
179+
180+
/**
181+
* Returns the resource filter information for the specified <code>filterId</code> by
182+
* the default factory.
183+
* <code>filterId</code> is case insensitive. If no matching filter is found, this
184+
* method returns <code>null</code>.
185+
* <p>
186+
* This operation is equivalent to <code>getDefaultInstance().filterInfo(filterId)</code>.
187+
*
188+
* @param filterId The resource filter ID, case insensitive.
189+
* @return the resource filter information for the specified <code>filterId</code>,
190+
* or <code>null</code> if no matching filter is found.
191+
*/
192+
public static FilterInfo getFilterInfo(String filterId) {
193+
return getDefaultInstance().filterInfo(filterId);
194+
}
195+
196+
/**
197+
* Returns an instance of {@link ResourceFilter} for the specified <code>filterId</code>
198+
* by the default factory.
199+
* <code>filterId</code> is case insensitive. If no matching filter is found, this
200+
* method returns <code>null</code>.
201+
* <p>
202+
* This operation is equivalent to <code>getDefaultInstance().resourceFilter(filterId)</code>.
203+
*
204+
* @param filterId The resource filter ID, case insensitive.
205+
* @return an instance of {@link ResourceFilter} for the specified <code>filterId</code>,
206+
* or <code>null</code> if no matching filter is found.
207+
*/
208+
public static ResourceFilter getResourceFilter(String filterId) {
209+
return getDefaultInstance().resourceFilter(filterId);
210+
}
211+
212+
/**
213+
* Returns an instance of {@link MultiBundleResourceFilter} for the specified <code>filterId</code>
214+
* by the default factory.
215+
* <code>filterId</code> is case insensitive. If no matching filter is found, this
216+
* method returns <code>null</code>.
217+
* <p>
218+
* This operation is equivalent to <code>getDefaultInstance().multiBundleResourceFilter(filterId)</code>.
219+
*
220+
* @param filterId The resource filter ID, case insensitive.
221+
* @return an instance of {@link MultiBundleResourceFilter} for the specified <code>filterId</code>,
222+
* or <code>null</code> if no matching filter is found.
223+
*/
224+
public static MultiBundleResourceFilter getMultiBundleResourceFilter(String filterId) {
225+
return getDefaultInstance().multiBundleResourceFilter(filterId);
226+
}
130227
}

gp-res-filter/src/test/java/com/ibm/g11n/pipeline/resfilter/ResourceFilterFactoryTest.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
public class ResourceFilterFactoryTest {
3535

3636
@Test
37-
public void testFactory() {
37+
public void testDefaultFactory() {
3838
Set<String> availableFilters = ResourceFilterFactory.getAvailableFilterIds();
3939
assertTrue("There should be some filters available by default", availableFilters.size() > 0);
4040

@@ -67,4 +67,44 @@ public void testFactory() {
6767
assert !availableFilters.contains(bogusId);
6868
assertNull("FilterInfo for bogus should not be available", ResourceFilterFactory.getFilterInfo(bogusId));
6969
}
70+
71+
@Test
72+
public void testFactory() {
73+
ResourceFilterFactory defFactory = ResourceFilterFactory.getDefaultInstance();
74+
ResourceFilterFactory myFactory = ResourceFilterFactory.getInstance(this.getClass().getClassLoader());
75+
76+
Set<String> defIds = defFactory.availableFilterIds();
77+
Set<String> myIds = myFactory.availableFilterIds();
78+
79+
assertTrue("Available IDs with default factory and local factory", defIds.equals(myIds));
80+
81+
for (String id : defIds) {
82+
Type defType = defFactory.filterInfo(id).getType();
83+
Type myType = myFactory.filterInfo(id).getType();
84+
assertTrue("Type for id:" + id, defType == myType);
85+
86+
switch (defType) {
87+
case SINGLE:
88+
assertNotNull("(defFactory) ResourceFilter should be available for " + id,
89+
defFactory.resourceFilter(id));
90+
assertNull("(defFactory) MultiBundleResourceFilter should not be available for " + id,
91+
defFactory.multiBundleResourceFilter(id));
92+
assertNotNull("(myFactory) ResourceFilter should be available for " + id,
93+
myFactory.resourceFilter(id));
94+
assertNull("(myFactory) MultiBundleResourceFilter should not be available for " + id,
95+
myFactory.multiBundleResourceFilter(id));
96+
break;
97+
case MULTI:
98+
assertNull("(defFactory) ResourceFilter should not be available for " + id,
99+
defFactory.resourceFilter(id));
100+
assertNotNull("(defFactory) MultiBundleResourceFilter should be available for " + id,
101+
defFactory.multiBundleResourceFilter(id));
102+
assertNull("(myFactory) ResourceFilter should not be available for " + id,
103+
myFactory.resourceFilter(id));
104+
assertNotNull("(myFactory) MultiBundleResourceFilter should be available for " + id,
105+
myFactory.multiBundleResourceFilter(id));
106+
break;
107+
}
108+
}
109+
}
70110
}

0 commit comments

Comments
 (0)