1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.datamodel.ifs2;
20
21 import java.io.IOException;
22 import java.io.UncheckedIOException;
23 import java.nio.file.FileAlreadyExistsException;
24 import java.nio.file.Files;
25 import java.nio.file.Path;
26 import java.nio.file.StandardCopyOption;
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.stream.Stream;
30
31 import org.apache.logging.log4j.LogManager;
32 import org.apache.logging.log4j.Logger;
33 import org.jdom2.Content;
34 import org.jdom2.Document;
35 import org.jdom2.Element;
36 import org.jdom2.JDOMException;
37 import org.mycore.common.content.MCRJDOMContent;
38 import org.mycore.common.content.MCRPathContent;
39 import org.mycore.datamodel.niofs.utils.MCRRecursiveDeleter;
40 import org.mycore.util.concurrent.MCRReadWriteGuard;
41 import org.xml.sax.SAXException;
42
43
44
45
46
47
48
49
50 public class MCRFileCollection extends MCRDirectory {
51
52
53
54
55 private static final Logger LOGGER = LogManager.getLogger(MCRFileCollection.class);
56
57 public static final String DATA_FILE = "mcrdata.xml";
58
59
60
61
62 private MCRStore store;
63
64
65
66
67 private int id;
68
69
70
71
72
73
74 private MCRReadWriteGuard dataGuard;
75
76
77
78
79
80
81
82
83
84
85
86
87 protected MCRFileCollection(MCRStore store, int id) throws IOException {
88 super(null, store.getSlot(id), new Element("collection"));
89 this.store = store;
90 this.id = id;
91 this.dataGuard = new MCRReadWriteGuard();
92 if (Files.exists(path)) {
93 readAdditionalData();
94 } else {
95 Files.createDirectories(path);
96 writeData(Document::new);
97 saveAdditionalData();
98 }
99 }
100
101 MCRReadWriteGuard getDataGuard() {
102 return dataGuard;
103 }
104
105 private void readAdditionalData() throws IOException {
106 Path src = path.resolve(DATA_FILE);
107 if (!Files.exists(src)) {
108 LOGGER.warn("Metadata file is missing, repairing metadata...");
109 writeData(e -> {
110 e.detach();
111 e.setName("collection");
112 e.removeContent();
113 new Document(e);
114 });
115 repairMetadata();
116 }
117 try {
118 Element parsed = new MCRPathContent(src).asXML().getRootElement();
119 writeData(e -> {
120 e.detach();
121 e.setName("collection");
122 e.removeContent();
123 List<Content> parsedContent = new ArrayList<>(parsed.getContent());
124 parsedContent.forEach(Content::detach);
125 e.addContent(parsedContent);
126 new Document(e);
127 });
128 } catch (JDOMException | SAXException e) {
129 throw new IOException(e);
130 }
131 }
132
133 protected void saveAdditionalData() throws IOException {
134 Path target = path.resolve(DATA_FILE);
135 try {
136 readData(e -> {
137 try {
138 boolean needsUpdate = true;
139 while (needsUpdate) {
140 try {
141 new MCRJDOMContent(e.getDocument()).sendTo(target, StandardCopyOption.REPLACE_EXISTING);
142 needsUpdate = false;
143 } catch (FileAlreadyExistsException ex) {
144
145 } catch (IOException | RuntimeException ex) {
146 throw ex;
147 }
148 }
149 return null;
150 } catch (IOException e1) {
151 throw new UncheckedIOException(e1);
152 }
153 });
154 } catch (UncheckedIOException e) {
155 throw e.getCause();
156 }
157 }
158
159 @Override
160 public Stream<MCRNode> getChildren() throws IOException {
161 return super.getChildren()
162 .filter(f -> !DATA_FILE.equals(f.getName()));
163 }
164
165
166
167
168 public void delete() throws IOException {
169 writeData(Element::removeContent);
170 Files.walkFileTree(path, MCRRecursiveDeleter.instance());
171 store.delete(id);
172 }
173
174
175
176
177
178 @Override
179 public void renameTo(String name) {
180 throw new UnsupportedOperationException("File collections can not be renamed");
181 }
182
183
184
185
186
187
188 public MCRStore getStore() {
189 return store;
190 }
191
192
193
194
195
196
197 public int getID() {
198 return id;
199 }
200
201
202
203
204
205
206
207 @Override
208 public MCRFileCollection getRoot() {
209 return this;
210 }
211
212 @Override
213 public MCRNode getChild(String name) {
214 if (DATA_FILE.equals(name)) {
215 return null;
216 } else {
217 return super.getChild(name);
218 }
219 }
220
221 @Override
222 public boolean hasChildren() throws IOException {
223 try (Stream<Path> stream = getUsableChildSream()) {
224 return stream.findAny().isPresent();
225 }
226 }
227
228 @Override
229 public int getNumChildren() throws IOException {
230 try (Stream<Path> stream = getUsableChildSream()) {
231 return Math.toIntExact(stream.count());
232 }
233 }
234
235 private Stream<Path> getUsableChildSream() throws IOException {
236 return Files.list(path)
237 .filter(p -> !DATA_FILE.equals(p.getFileName().toString()));
238 }
239
240 @Override
241 public String getName() {
242 return "";
243 }
244
245
246
247
248
249 @Override
250 public void repairMetadata() throws IOException {
251 super.repairMetadata();
252 writeData(e -> {
253 e.setName("collection");
254 e.removeAttribute("name");
255 });
256 saveAdditionalData();
257 }
258
259
260
261
262
263 Document getMetadata() {
264 return new Document(readData(Element::clone));
265 }
266
267 }