1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.pi.handle;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Base64;
24 import java.util.Date;
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.Optional;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.locks.ReentrantLock;
30 import java.util.function.Predicate;
31
32 import org.jdom2.Document;
33 import org.mycore.backend.jpa.MCREntityManagerProvider;
34 import org.mycore.common.config.annotation.MCRProperty;
35 import org.mycore.common.content.MCRContent;
36 import org.mycore.common.content.MCRJDOMContent;
37 import org.mycore.common.content.transformer.MCRContentTransformer;
38 import org.mycore.common.content.transformer.MCRContentTransformerFactory;
39 import org.mycore.datamodel.metadata.MCRBase;
40 import org.mycore.datamodel.metadata.MCRMetadataManager;
41 import org.mycore.datamodel.metadata.MCRObjectID;
42 import org.mycore.frontend.MCRFrontendUtil;
43 import org.mycore.pi.MCRPIJobService;
44 import org.mycore.pi.backend.MCRPI;
45 import org.mycore.pi.exceptions.MCRPersistentIdentifierException;
46
47 public class MCREpicService extends MCRPIJobService<MCRHandle> {
48
49 public static final String EPIC_KEY = "EPIC";
50
51 public static final String OBJECT_ID_KEY = "ObjectID";
52
53
54
55
56 @MCRProperty(name = "Username")
57 public String username;
58
59
60
61
62 @MCRProperty(name = "Password")
63 public String password;
64
65
66
67
68 @MCRProperty(name = "Endpoint")
69 public String endpoint;
70
71
72
73
74 @MCRProperty(name = "BaseURL", required = false)
75 public String baseURL;
76
77
78
79
80
81 @MCRProperty(name = "Transformer", required = false)
82 public String transformerID = null;
83
84
85
86
87 @MCRProperty(name = "MetadataType", required = false)
88 public String metadataType = null;
89
90
91
92
93 @MCRProperty(name = "MetadataIndex", required = false)
94 public String metadataIndex = null;
95
96 public ConcurrentHashMap<String, ReentrantLock> idLockMap = new ConcurrentHashMap<>();
97
98 public MCREpicService() {
99 super("handle");
100 }
101
102 @Override
103 public MCRPI insertIdentifierToDatabase(MCRBase obj, String additional,
104 MCRHandle identifier) {
105 Date registrationStarted = null;
106 if (getRegistrationPredicate().test(obj)) {
107 registrationStarted = new Date();
108 startRegisterJob(obj, identifier);
109 }
110
111 MCRPI databaseEntry = new MCRPI(identifier.asString(), getType(), obj.getId().toString(), additional,
112 this.getServiceID(), provideRegisterDate(obj, additional), registrationStarted);
113 MCREntityManagerProvider.getCurrentEntityManager().persist(databaseEntry);
114 return databaseEntry;
115 }
116
117 @Override
118 protected void registerIdentifier(MCRBase obj, String additional, MCRHandle pi)
119 throws MCRPersistentIdentifierException {
120 if (!"".equals(additional)) {
121 String className = this.getClass().getName();
122 throw new MCRPersistentIdentifierException(
123 className + " doesn't support additional information! (" + additional + ")");
124 }
125 }
126
127 @Override
128 protected void delete(MCRHandle identifier, MCRBase obj, String additional)
129 throws MCRPersistentIdentifierException {
130 this.startDeleteJob(obj, identifier);
131 }
132
133 @Override
134 protected void update(MCRHandle identifier, MCRBase obj, String additional)
135 throws MCRPersistentIdentifierException {
136 if (!this.hasRegistrationStarted(obj.getId(), additional)) {
137 Predicate<MCRBase> registrationCondition = this.getRegistrationPredicate();
138 if (registrationCondition.test(obj)) {
139 this.updateStartRegistrationDate(obj.getId(), "", new Date());
140 this.startRegisterJob(obj, identifier);
141 }
142 } else if (this.isRegistered(obj.getId(), "")) {
143 this.startUpdateJob(obj, identifier);
144 }
145 }
146
147 @Override
148 protected void deleteJob(Map<String, String> parameters) throws MCRPersistentIdentifierException {
149 String epic = parameters.get(EPIC_KEY);
150
151 try {
152 getClient().delete(new MCRHandle(epic));
153 } catch (IOException e) {
154 throw new MCRPersistentIdentifierException("Error while communicating with epic service", e);
155 }
156 }
157
158 @Override
159 protected void updateJob(Map<String, String> parameters) throws MCRPersistentIdentifierException {
160 String epic = parameters.get(EPIC_KEY);
161 String objId = parameters.get(OBJECT_ID_KEY);
162
163 createOrUpdate(epic, objId);
164 }
165
166 private void createOrUpdate(String epic, String objId) throws MCRPersistentIdentifierException {
167 new ReentrantLock();
168
169 final MCRObjectID objectID = MCRObjectID.getInstance(objId);
170 if (!MCRMetadataManager.exists(objectID)) {
171 return;
172 }
173
174 validateJobUserRights(objectID);
175
176 final MCRHandle mcrHandle = new MCRHandle(epic);
177 final String urlForObject = getURLForObject(objId);
178
179 try {
180 final ArrayList<MCRHandleInfo> handleInfos = new ArrayList<>();
181 processMedataData(objectID, handleInfos);
182
183 ReentrantLock reentrantLock = idLockMap.computeIfAbsent(epic, (l) -> new ReentrantLock());
184 try {
185 reentrantLock.lock();
186 getClient().create(urlForObject, mcrHandle, handleInfos);
187 } finally {
188 reentrantLock.unlock();
189 }
190 } catch (IOException e) {
191 throw new MCRPersistentIdentifierException("Error while communicating with EPIC Service", e);
192 }
193
194 }
195
196 private void processMedataData(MCRObjectID objectID, ArrayList<MCRHandleInfo> handleInfos) throws IOException {
197 if (transformerID != null && metadataType != null && metadataIndex != null) {
198 final int index = Integer.parseInt(metadataIndex, 10);
199 final Document xml = MCRMetadataManager.retrieve(objectID).createXML();
200 final MCRContentTransformer transformer = MCRContentTransformerFactory.getTransformer(transformerID);
201 final MCRContent result = transformer.transform(new MCRJDOMContent(xml));
202 final byte[] bytes = result.asByteArray();
203 final String encodedData = Base64.getEncoder().encodeToString(bytes);
204
205 final MCRHandleInfo metadataInfo = new MCRHandleInfo();
206 metadataInfo.setIdx(index);
207 metadataInfo.setData(encodedData);
208 metadataInfo.setType(metadataType);
209 handleInfos.add(metadataInfo);
210 }
211 }
212
213 protected String getURLForObject(String objectId) {
214 String baseURL = this.baseURL != null ? this.baseURL : MCRFrontendUtil.getBaseURL();
215 return baseURL + "receive/" + objectId;
216
217 }
218
219 @Override
220 protected void registerJob(Map<String, String> parameters) throws MCRPersistentIdentifierException {
221 String epic = parameters.get(EPIC_KEY);
222 String objId = parameters.get(OBJECT_ID_KEY);
223
224 createOrUpdate(epic, objId);
225 }
226
227 @Override
228 protected Optional<String> getJobInformation(Map<String, String> contextParameters) {
229 return Optional.empty();
230 }
231
232 private void startUpdateJob(MCRBase obj, MCRHandle epic) {
233 HashMap<String, String> contextParameters = new HashMap<String, String>();
234 contextParameters.put(EPIC_KEY, epic.asString());
235 contextParameters.put(OBJECT_ID_KEY, obj.getId().toString());
236 this.addUpdateJob(contextParameters);
237 }
238
239 private void startRegisterJob(MCRBase obj, MCRHandle epic) {
240 HashMap<String, String> contextParameters = new HashMap<String, String>();
241 contextParameters.put(EPIC_KEY, epic.asString());
242 contextParameters.put(OBJECT_ID_KEY, obj.getId().toString());
243 this.addRegisterJob(contextParameters);
244 }
245
246 private void startDeleteJob(MCRBase obj, MCRHandle epic) {
247 HashMap<String, String> contextParameters = new HashMap<String, String>();
248 contextParameters.put(EPIC_KEY, epic.asString());
249 contextParameters.put(OBJECT_ID_KEY, obj.getId().toString());
250 this.addDeleteJob(contextParameters);
251 }
252
253 private MCREpicClient getClient() {
254 return new MCREpicClient(username, password, endpoint);
255 }
256
257 }