1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
package bjc.utils.components;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.function.BiPredicate;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import bjc.utils.data.IHolder;
import bjc.utils.data.Identity;
import bjc.utils.funcdata.FunctionalList;
import bjc.utils.funcdata.FunctionalMap;
import bjc.utils.funcdata.IFunctionalList;
import bjc.utils.funcdata.IFunctionalMap;
import bjc.utils.funcutils.FileUtils;
/**
* A component repository that loads its components from files in a
* directory
*
* @author ben
*
* @param <E>
* The type of component being read in
*/
public class FileComponentRepository<E extends IDescribedComponent>
implements IComponentRepository<E> {
private static final Logger CLASS_LOGGER =
LoggerFactory.getLogger(FileComponentRepository.class);
/**
* The internal storage of components
*/
private IFunctionalMap<String, E> components;
/**
* The path that all the components came from
*/
private Path sourceDirectory;
/**
* Create a new component repository sourcing components from files in
* a directory
*
* An exception thrown during the loading of a component will only
* cause the loading of that component to fail, but a warning will be
* logged.
*
* @param directory
* The directory to read component files from
* @param componentReader
* The function to use to convert files to components
*/
public FileComponentRepository(File directory,
Function<File, E> componentReader) {
if (!directory.isDirectory()) {
throw new IllegalArgumentException("File " + directory
+ " is not a directory.\n"
+ "Components can only be read from a directory");
}
components = new FunctionalMap<>();
sourceDirectory = directory.toPath().toAbsolutePath();
IHolder<Boolean> isFirstDir = new Identity<>(true);
BiPredicate<Path, BasicFileAttributes> firstLevelTraverser =
(pth, attr) -> {
if (attr.isDirectory() && !isFirstDir.getValue()) {
// Don't skip the first directory, that's the
// parent
isFirstDir.replace(false);
// Skip directories, they probably have
// component
return false;
}
return true;
};
try {
FileUtils.traverseDirectory(sourceDirectory,
firstLevelTraverser, (pth, attr) -> {
loadComponent(componentReader, pth);
// Keep loading components, even if this one failed
return true;
});
} catch (IOException ioex) {
CLASS_LOGGER.warn("Error found reading component from file.",
ioex);
}
}
private void loadComponent(Function<File, E> componentReader,
Path pth) {
try {
E component = componentReader.apply(pth.toFile());
if (component == null) {
throw new NullPointerException(
"Component reader read null component");
} else if (!components.containsKey(component.getName())) {
components.put(component.getName(), component);
} else {
CLASS_LOGGER.warn("Found a duplicate component.\n"
+ "Multiple versions of the same component are not currently supported.\n"
+ "The component" + component
+ " will not be registered .");
}
} catch (Exception ex) {
CLASS_LOGGER.warn("Error found reading component from file "
+ pth.toString()
+ ". This component will not be loaded", ex);
}
}
@Override
public IFunctionalList<E> getComponentList() {
IFunctionalList<E> returnedList = new FunctionalList<>();
components
.forEach((name, component) -> returnedList.add(component));
return returnedList;
}
@Override
public IFunctionalMap<String, E> getComponents() {
return components;
}
@Override
public String getSource() {
return "Components read from directory " + sourceDirectory + ".";
}
@Override
public E getComponentByName(String name) {
return components.get(name);
}
}
|