1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.mets.model;
20
21 import java.io.IOException;
22 import java.net.URISyntaxException;
23 import java.nio.file.DirectoryStream;
24 import java.nio.file.Files;
25 import java.nio.file.Path;
26 import java.nio.file.attribute.BasicFileAttributes;
27 import java.util.Arrays;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.SortedMap;
33 import java.util.TreeMap;
34
35 import org.apache.logging.log4j.LogManager;
36 import org.apache.logging.log4j.Logger;
37 import org.mycore.common.MCRException;
38 import org.mycore.common.config.MCRConfiguration2;
39 import org.mycore.common.config.MCRConfigurationException;
40 import org.mycore.common.xml.MCRXMLFunctions;
41 import org.mycore.datamodel.metadata.MCRDerivate;
42 import org.mycore.datamodel.metadata.MCRMetadataManager;
43 import org.mycore.datamodel.metadata.MCRObjectID;
44 import org.mycore.datamodel.niofs.MCRContentTypes;
45 import org.mycore.datamodel.niofs.MCRPath;
46 import org.mycore.mets.model.files.FLocat;
47 import org.mycore.mets.model.files.File;
48 import org.mycore.mets.model.files.FileGrp;
49 import org.mycore.mets.model.files.FileSec;
50 import org.mycore.mets.model.sections.AmdSec;
51 import org.mycore.mets.model.sections.DmdSec;
52 import org.mycore.mets.model.struct.Fptr;
53 import org.mycore.mets.model.struct.LOCTYPE;
54 import org.mycore.mets.model.struct.LogicalDiv;
55 import org.mycore.mets.model.struct.LogicalStructMap;
56 import org.mycore.mets.model.struct.PhysicalDiv;
57 import org.mycore.mets.model.struct.PhysicalStructMap;
58 import org.mycore.mets.model.struct.PhysicalSubDiv;
59 import org.mycore.mets.model.struct.SmLink;
60 import org.mycore.mets.model.struct.StructLink;
61 import org.mycore.mets.tools.MCRMetsSave;
62 import org.mycore.services.i18n.MCRTranslation;
63
64
65
66
67
68
69
70 public class MCRMETSDefaultGenerator extends MCRMETSAbstractGenerator {
71
72 private static final Logger LOGGER = LogManager.getLogger(MCRMETSGenerator.class);
73
74 private static final List<String> EXCLUDED_ROOT_FOLDERS = Arrays.asList("alto", "tei");
75
76 private HashMap<String, String> hrefIdMap = new HashMap<>();
77
78 @Override
79 public Mets generate() throws MCRException {
80 try {
81 Mets mets = createMets();
82 MCRDerivate owner = MCRMetadataManager.retrieveMCRDerivate(MCRObjectID.getInstance(getOwner()));
83
84 mets.getLogicalStructMap().getDivContainer().setLabel(
85 MCRTranslation.exists("MCR.Mets.LogicalStructMap.Default.Label")
86 ? MCRTranslation.translate("MCR.Mets.LogicalStructMap.Default.Label")
87 : owner.getId().toString());
88
89 Map<String, String> urnFileMap = owner.getUrnMap();
90 if (urnFileMap.size() > 0) {
91 try {
92 MCRMetsSave.updateURNsInMetsDocument(mets, urnFileMap);
93 } catch (Exception e) {
94 LOGGER.error("error while adding urn´s to new Mets file", e);
95 }
96 }
97 return mets;
98 } catch (Exception ioExc) {
99 throw new MCRException("Unable to create mets.xml of " + getOwner(), ioExc);
100 }
101 }
102
103 private Mets createMets() throws IOException {
104 Mets mets = new Mets();
105 String owner = getOwner();
106
107
108 DmdSec dmdSec = new DmdSec("dmd_" + owner);
109
110 AmdSec amdSec = new AmdSec("amd_" + owner);
111
112 FileSec fileSec = new FileSec();
113
114
115
116
117
118
119 PhysicalStructMap physicalStructMap = new PhysicalStructMap();
120 PhysicalDiv physicalDiv = new PhysicalDiv("phys_" + owner, "physSequence");
121 physicalStructMap.setDivContainer(physicalDiv);
122
123
124 MCRILogicalStructMapTypeProvider typeProvider = getTypeProvider();
125 LogicalStructMap logicalStructMap = new LogicalStructMap();
126
127 LogicalDiv logicalDiv = new LogicalDiv("log_" + owner, typeProvider.getType(MCRObjectID.getInstance(owner)),
128 owner, amdSec.getId(), dmdSec.getId());
129 logicalDiv.setDmdId(dmdSec.getId());
130 logicalStructMap.setDivContainer(logicalDiv);
131
132 StructLink structLink = new StructLink();
133
134
135 structureMets(getDerivatePath(), getIgnorePaths(), fileSec, physicalDiv, logicalDiv, structLink, 0);
136 hrefIdMap.clear();
137
138
139 mets.addDmdSec(dmdSec);
140 mets.addAmdSec(amdSec);
141 mets.setFileSec(fileSec);
142 mets.addStructMap(physicalStructMap);
143 mets.addStructMap(logicalStructMap);
144 mets.setStructLink(structLink);
145
146 return mets;
147 }
148
149 private void structureMets(MCRPath dir, Set<MCRPath> ignoreNodes, FileSec fileSec, PhysicalDiv physicalDiv,
150 LogicalDiv logicalDiv, StructLink structLink, int logOrder) throws IOException {
151 int lOrder = logOrder;
152 SortedMap<MCRPath, BasicFileAttributes> files = new TreeMap<>();
153 SortedMap<MCRPath, BasicFileAttributes> directories = new TreeMap<>();
154
155 fillFileMap(ignoreNodes, files, directories, dir);
156
157 for (Map.Entry<MCRPath, BasicFileAttributes> file : files.entrySet()) {
158 createStructure(dir, fileSec, physicalDiv, logicalDiv, structLink, file);
159 }
160 for (Map.Entry<MCRPath, BasicFileAttributes> directory : directories.entrySet()) {
161 String dirName = directory.getKey().getFileName().toString();
162 if (isInExcludedRootFolder(directory.getKey())) {
163 structureMets(directory.getKey(), ignoreNodes, fileSec, physicalDiv, logicalDiv, structLink, lOrder);
164 } else {
165 LogicalDiv section = new LogicalDiv("log_" + ++lOrder, "section", dirName);
166 logicalDiv.add(section);
167 structureMets(directory.getKey(), ignoreNodes, fileSec, physicalDiv, section, structLink, lOrder);
168 }
169 }
170 }
171
172 private void createStructure(MCRPath dir, FileSec fileSec, PhysicalDiv physicalDiv, LogicalDiv logicalDiv,
173 StructLink structLink, Map.Entry<MCRPath, BasicFileAttributes> file) throws IOException {
174 String baseID = MCRMetsSave.getFileBase(file.getKey());
175 final String physicalID = "phys_" + baseID;
176 final String href;
177 String path = file.getKey().getOwnerRelativePath().substring(1);
178 try {
179 href = MCRXMLFunctions.encodeURIPath(path, true);
180 } catch (URISyntaxException uriSyntaxException) {
181 LOGGER.error("invalid href {}", path, uriSyntaxException);
182 return;
183 }
184 int beginIndex = href.lastIndexOf("/") == -1 ? 0 : href.lastIndexOf("/") + 1;
185 int endIndex = (href.lastIndexOf(".") == -1 || href.lastIndexOf(".") <= beginIndex) ? href.length()
186 : href.lastIndexOf(".");
187 String fileName = href.substring(beginIndex, endIndex);
188 LOGGER.debug("Created fileName: {}", fileName);
189
190 if (!(hrefIdMap.containsKey(fileName) || hrefIdMap.containsValue(baseID)
191 && isInExcludedRootFolder(dir))) {
192 hrefIdMap.put(fileName, baseID);
193 }
194
195
196 String fileUse = MCRMetsModelHelper.getUseForHref(href)
197 .orElseThrow(() -> new MCRConfigurationException("Could not create METS!"));
198 String fileID = fileUse.replace('.', '_') + "_" + baseID;
199 sortFileToGrp(fileSec, file, fileID, href, fileUse);
200
201
202 buildPhysDivs(dir, physicalDiv, fileID, physicalID, fileName);
203
204
205 if (!isInExcludedRootFolder(dir)) {
206 SmLink smLink = new SmLink(logicalDiv.getId(), physicalID);
207 structLink.addSmLink(smLink);
208 }
209 }
210
211 private void fillFileMap(Set<MCRPath> ignoreNodes, SortedMap<MCRPath, BasicFileAttributes> files,
212 SortedMap<MCRPath, BasicFileAttributes> directories, Path dir) throws IOException {
213 try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(dir)) {
214 for (Path child : dirStream) {
215 MCRPath path = MCRPath.toMCRPath(child);
216 if (ignoreNodes.contains(path)) {
217 continue;
218 }
219 BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
220 if (attrs.isDirectory()) {
221 directories.put(path, attrs);
222 } else {
223 files.put(path, attrs);
224 }
225 }
226 }
227 }
228
229 private void buildPhysDivs(MCRPath dir, PhysicalDiv physicalDiv, String fileID, final String physicalID,
230 String fileName) {
231 if (!fileName.isEmpty() && hrefIdMap.containsKey(fileName) && isInExcludedRootFolder(dir)) {
232 for (PhysicalSubDiv physSubDiv : physicalDiv.getChildren()) {
233 if (physSubDiv.getId().contains(hrefIdMap.get(fileName))) {
234 physSubDiv.add(new Fptr(fileID));
235 }
236 }
237 } else {
238 PhysicalSubDiv pyhsicalPage = new PhysicalSubDiv(physicalID, "page");
239 Fptr fptr = new Fptr(fileID);
240 pyhsicalPage.add(fptr);
241 physicalDiv.add(pyhsicalPage);
242 }
243 }
244
245 private void sortFileToGrp(FileSec fileSec, Map.Entry<MCRPath, BasicFileAttributes> file, String fileID,
246 final String href, String fileUse) throws IOException {
247
248 File metsFile = new File(fileID, MCRContentTypes.probeContentType(file.getKey()));
249 FLocat fLocat = new FLocat(LOCTYPE.URL, href);
250 metsFile.setFLocat(fLocat);
251
252 this.createOrGetGroup(fileSec, fileUse).addFile(metsFile);
253 }
254
255 private FileGrp createOrGetGroup(FileSec fileSec, String fileUse) {
256 FileGrp fileGroup = fileSec.getFileGroup(fileUse);
257 if (fileGroup == null) {
258 fileGroup = new FileGrp(fileUse);
259 fileSec.addFileGrp(fileGroup);
260 }
261 return fileGroup;
262 }
263
264
265
266
267
268
269
270 private boolean isInExcludedRootFolder(MCRPath directory) {
271 for (String excludedRoot : EXCLUDED_ROOT_FOLDERS) {
272 String path = directory.toString().substring(directory.toString().indexOf(":/") + 2);
273 if (path.startsWith(excludedRoot)) {
274 return true;
275 }
276 }
277 return false;
278 }
279
280 private MCRILogicalStructMapTypeProvider getTypeProvider() {
281 try {
282 return MCRConfiguration2.<MCRDefaultLogicalStructMapTypeProvider>getClass(
283 "MCR.Component.MetsMods.LogicalStructMapTypeProvider")
284 .orElse(MCRDefaultLogicalStructMapTypeProvider.class).getDeclaredConstructor().newInstance();
285 } catch (Exception e) {
286 LOGGER.warn("Could not load class", e);
287 return new MCRDefaultLogicalStructMapTypeProvider();
288 }
289 }
290
291 }