View Javadoc
1   /*
2    * This file is part of ***  M y C o R e  ***
3    * See http://www.mycore.de/ for details.
4    *
5    * MyCoRe is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * MyCoRe is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with MyCoRe.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package org.mycore.pi.urn;
20  
21  import java.io.IOException;
22  import java.nio.file.Files;
23  import java.nio.file.Path;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.Date;
27  import java.util.List;
28  import java.util.function.Predicate;
29  import java.util.regex.Pattern;
30  import java.util.stream.Collectors;
31  
32  import org.apache.logging.log4j.LogManager;
33  import org.apache.logging.log4j.Logger;
34  import org.mycore.access.MCRAccessException;
35  import org.mycore.backend.jpa.MCREntityManagerProvider;
36  import org.mycore.datamodel.common.MCRActiveLinkException;
37  import org.mycore.datamodel.metadata.MCRBase;
38  import org.mycore.datamodel.metadata.MCRDerivate;
39  import org.mycore.datamodel.metadata.MCRMetadataManager;
40  import org.mycore.datamodel.metadata.MCRObjectDerivate;
41  import org.mycore.datamodel.niofs.MCRPath;
42  import org.mycore.datamodel.niofs.utils.MCRFileCollectingFileVisitor;
43  import org.mycore.pi.MCRPIManager;
44  import org.mycore.pi.MCRPIService;
45  import org.mycore.pi.backend.MCRPI;
46  import org.mycore.pi.exceptions.MCRPersistentIdentifierException;
47  
48  import jakarta.persistence.EntityManager;
49  
50  /**
51   * Service for assigning granular URNs to Derivate. You can call it with a Derivate-ID and it will assign a Base-URN for
52   * the Derivate and granular URNs for every file in the Derivate (except IgnoreFileNames). If you then add a file to
53   * Derivate you can call with Derivate-ID and additional path of the file. E.g. mir_derivate_00000060 and /image1.jpg
54   * <p> <b>Inscriber is ignored with this {@link MCRPIService}</b> </p> Configuration Parameter(s): <dl>
55   * <dt>IgnoreFileNames</dt> <dd>Comma seperated list of regex file which should not have a urn assigned. Default:
56   * mets\\.xml</dd> </dl>
57   */
58  public class MCRURNGranularOAIService extends MCRPIService<MCRDNBURN> {
59  
60      private static final Logger LOGGER = LogManager.getLogger();
61  
62      public MCRURNGranularOAIService() {
63          super(MCRDNBURN.TYPE);
64      }
65  
66      @Override
67      public MCRDNBURN register(MCRBase obj, String additional, boolean updateObject)
68          throws MCRAccessException, MCRActiveLinkException, MCRPersistentIdentifierException {
69          this.validateRegistration(obj, additional);
70  
71          MCRObjectDerivate derivate = ((MCRDerivate) obj).getDerivate();
72          MCRDNBURN newURN;
73  
74          if (additional.equals("")) {
75              /* Multiple URN for entire Derivate...  */
76              newURN = registerURNsDerivate(obj, additional, derivate);
77          } else {
78              /* Single URN to one File... */
79              newURN = registerSingleURN(obj, additional, derivate);
80          }
81  
82          try {
83              MCRMetadataManager.update(obj);
84          } catch (Exception e) {
85              throw new MCRPersistentIdentifierException("Error while updating derivate " + obj.getId(), e);
86          }
87  
88          return newURN;
89  
90      }
91  
92      private MCRDNBURN registerSingleURN(MCRBase obj, String additional, MCRObjectDerivate derivate)
93          throws MCRPersistentIdentifierException {
94          LOGGER.info("Add single urn to {} / {}", obj.getId(), additional);
95  
96          EntityManager em = MCREntityManagerProvider.getCurrentEntityManager();
97          MCRPath filePath = MCRPath.getPath(obj.getId().toString(), additional);
98          if (!Files.exists(filePath)) {
99              throw new MCRPersistentIdentifierException("Invalid path : " + additional);
100         }
101 
102         int count = Math.toIntExact(derivate.getFileMetadata().stream().filter(file -> file.getUrn() != null).count());
103         MCRDNBURN newURN = (MCRDNBURN) MCRPIManager.getInstance().get(derivate.getURN())
104             .findFirst().get();
105 
106         String setID = obj.getId().getNumberAsString();
107         MCRDNBURN urntoAssign = newURN.toGranular(setID, count + 1, count + 1);
108         derivate.getOrCreateFileMetadata(filePath, urntoAssign.asString()).setUrn(urntoAssign.asString());
109         MCRPI databaseEntry = new MCRPI(urntoAssign.asString(), getType(), obj.getId().toString(), additional,
110             this.getServiceID(), new Date());
111         em.persist(databaseEntry);
112         return newURN;
113     }
114 
115     private MCRDNBURN registerURNsDerivate(MCRBase obj, String additional, MCRObjectDerivate derivate)
116         throws MCRPersistentIdentifierException {
117         LOGGER.info("Add URNs to all files of {}", obj.getId());
118 
119         EntityManager em = MCREntityManagerProvider.getCurrentEntityManager();
120 
121         Path path = MCRPath.getPath(obj.getId().toString(), "/");
122         MCRFileCollectingFileVisitor<Path> collectingFileVisitor = new MCRFileCollectingFileVisitor<>();
123 
124         try {
125             Files.walkFileTree(path, collectingFileVisitor);
126         } catch (IOException e) {
127             throw new MCRPersistentIdentifierException("Could not walk derivate file tree!", e);
128         }
129 
130         List<String> ignoreFileNamesList = getIgnoreFileList();
131 
132         List<Predicate<String>> predicateList = ignoreFileNamesList
133             .stream()
134             .map(Pattern::compile)
135             .map(Pattern::asPredicate)
136             .collect(Collectors.toList());
137 
138         List<MCRPath> pathList = collectingFileVisitor
139             .getPaths()
140             .stream()
141             .filter(file -> predicateList.stream()
142                 .noneMatch(p -> p.test(file.toString().split(":")[1])))
143             .map(p -> (MCRPath) p)
144             .sorted()
145             .collect(Collectors.toList());
146 
147         MCRDNBURN newURN = getNewIdentifier(obj, additional);
148         String setID = obj.getId().getNumberAsString();
149 
150         for (int pathListIndex = 0; pathListIndex < pathList.size(); pathListIndex++) {
151             MCRDNBURN subURN = newURN.toGranular(setID, pathListIndex + 1, pathList.size());
152             derivate.getOrCreateFileMetadata(pathList.get(pathListIndex), subURN.asString()).setUrn(subURN.asString());
153             MCRPI databaseEntry = new MCRPI(subURN.asString(), getType(), obj.getId().toString(),
154                 pathList.get(pathListIndex).getOwnerRelativePath(),
155                 this.getServiceID(), null);
156             em.persist(databaseEntry);
157         }
158 
159         derivate.setURN(newURN.asString());
160         MCRPI databaseEntry = new MCRPI(newURN.asString(), getType(), obj.getId().toString(), "",
161             this.getServiceID(), new Date());
162         em.persist(databaseEntry);
163         return newURN;
164     }
165 
166     private List<String> getIgnoreFileList() {
167         List<String> ignoreFileNamesList = new ArrayList<>();
168         String ignoreFileNames = getProperties().get("IgnoreFileNames");
169         if (ignoreFileNames != null) {
170             ignoreFileNamesList.addAll(Arrays.asList(ignoreFileNames.split(",")));
171         } else {
172             ignoreFileNamesList.add("mets\\.xml"); // default value
173         }
174         return ignoreFileNamesList;
175     }
176 
177     @Override
178     protected void registerIdentifier(MCRBase obj, String additional, MCRDNBURN urn)
179         throws MCRPersistentIdentifierException {
180         // not used in this impl
181     }
182 
183     @Override
184     protected void delete(MCRDNBURN identifier, MCRBase obj, String additional)
185         throws MCRPersistentIdentifierException {
186         throw new MCRPersistentIdentifierException("Delete is not supported for " + getType());
187     }
188 
189     @Override
190     protected void update(MCRDNBURN identifier, MCRBase obj, String additional)
191         throws MCRPersistentIdentifierException {
192         //TODO: improve API, don't override method to do nothing
193         LOGGER.info("No update in this implementation");
194     }
195 }