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.File;
22 import java.io.IOException;
23 import java.net.URI;
24 import java.net.URISyntaxException;
25 import java.nio.file.Path;
26 import java.util.Iterator;
27
28 import org.apache.logging.log4j.LogManager;
29 import org.apache.logging.log4j.Logger;
30 import org.jdom2.JDOMException;
31 import org.mycore.common.MCRPersistenceException;
32 import org.mycore.common.MCRSessionMgr;
33 import org.mycore.common.config.MCRConfiguration2;
34 import org.mycore.common.config.MCRConfigurationException;
35 import org.mycore.common.content.MCRContent;
36 import org.tmatesoft.svn.core.SVNCancelException;
37 import org.tmatesoft.svn.core.SVNCommitInfo;
38 import org.tmatesoft.svn.core.SVNException;
39 import org.tmatesoft.svn.core.SVNURL;
40 import org.tmatesoft.svn.core.auth.BasicAuthenticationManager;
41 import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
42 import org.tmatesoft.svn.core.auth.SVNAuthentication;
43 import org.tmatesoft.svn.core.auth.SVNUserNameAuthentication;
44 import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
45 import org.tmatesoft.svn.core.io.ISVNEditor;
46 import org.tmatesoft.svn.core.io.SVNRepository;
47 import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
48 import org.tmatesoft.svn.core.wc.SVNEvent;
49 import org.tmatesoft.svn.core.wc.admin.ISVNAdminEventHandler;
50 import org.tmatesoft.svn.core.wc.admin.SVNAdminClient;
51 import org.tmatesoft.svn.core.wc.admin.SVNAdminEvent;
52
53
54
55
56
57
58
59
60
61
62 public class MCRVersioningMetadataStore extends MCRMetadataStore {
63
64 protected static final Logger LOGGER = LogManager.getLogger(MCRVersioningMetadataStore.class);
65
66 protected SVNURL repURL;
67
68 protected static final boolean SYNC_LAST_MODIFIED_ON_SVN_COMMIT = MCRConfiguration2
69 .getBoolean("MCR.IFS2.SyncLastModifiedOnSVNCommit").orElse(true);
70
71 static {
72 FSRepositoryFactory.setup();
73 }
74
75 @Override
76 protected void init(String type) {
77 super.init(type);
78 setupSVN(type);
79 }
80
81 @Override
82 protected void init(MCRStoreConfig config) {
83 super.init(config);
84 setupSVN(config.getID());
85 }
86
87 private void setupSVN(String type) {
88 URI repositoryURI;
89 String repositoryURIString = MCRConfiguration2.getStringOrThrow("MCR.IFS2.Store." + type + ".SVNRepositoryURL");
90 try {
91 repositoryURI = new URI(repositoryURIString);
92 } catch (URISyntaxException e) {
93 String msg = "Syntax error in MCR.IFS2.Store." + type + ".SVNRepositoryURL property: "
94 + repositoryURIString;
95 throw new MCRConfigurationException(msg, e);
96 }
97 try {
98 LOGGER.info("Versioning metadata store {} repository URL: {}", type, repositoryURI);
99 repURL = SVNURL.create(repositoryURI.getScheme(), repositoryURI.getUserInfo(), repositoryURI.getHost(),
100 repositoryURI.getPort(), repositoryURI.getPath(), true);
101 LOGGER.info("repURL: {}", repURL);
102 File dir = new File(repURL.getPath());
103 if (!dir.exists() || (dir.isDirectory() && dir.list().length == 0)) {
104 LOGGER.info("Repository does not exist, creating new SVN repository at {}", repositoryURI);
105 repURL = SVNRepositoryFactory.createLocalRepository(dir, true, false);
106 }
107 } catch (SVNException ex) {
108 String msg = "Error initializing SVN repository at URL " + repositoryURI;
109 throw new MCRConfigurationException(msg, ex);
110 }
111 }
112
113
114
115
116
117
118
119
120
121
122 public static boolean shouldSyncLastModifiedOnSVNCommit() {
123 return SYNC_LAST_MODIFIED_ON_SVN_COMMIT;
124 }
125
126
127
128
129
130
131
132
133 SVNRepository getRepository() throws SVNException {
134 SVNRepository repository = SVNRepositoryFactory.create(repURL);
135 String user = MCRSessionMgr.getCurrentSession().getUserInformation().getUserID();
136 SVNAuthentication[] auth = {
137 SVNUserNameAuthentication.newInstance(user, false, repURL, false) };
138 BasicAuthenticationManager authManager = new BasicAuthenticationManager(auth);
139 repository.setAuthenticationManager(authManager);
140 return repository;
141 }
142
143
144
145
146
147
148
149
150 SVNURL getRepositoryURL() {
151 return repURL;
152 }
153
154
155
156
157
158 public void verify() throws MCRPersistenceException {
159 String replURLStr = repURL.toString();
160 if (!repURL.getProtocol().equals("file")) {
161 LOGGER.warn("Cannot verify non local SVN repository '{}'.", replURLStr);
162 return;
163 }
164 try {
165 SVNRepository repository = getRepository();
166 long latestRevision = repository.getLatestRevision();
167 if (latestRevision == 0) {
168 LOGGER.warn("Cannot verify SVN repository '{}' with no revisions.", replURLStr);
169 }
170 ISVNAuthenticationManager authenticationManager = repository.getAuthenticationManager();
171 SVNAdminClient adminClient = new SVNAdminClient(authenticationManager, null);
172 File repositoryRoot = new File(URI.create(replURLStr));
173 adminClient.setEventHandler(new ISVNAdminEventHandler() {
174
175 int batchSize = 100;
176
177 @Override
178 public void checkCancelled() throws SVNCancelException {
179 }
180
181 @Override
182 public void handleEvent(SVNEvent event, double progress) throws SVNException {
183 }
184
185 @Override
186 public void handleAdminEvent(SVNAdminEvent event, double progress) throws SVNException {
187 if (event.getMessage() != null) {
188 if (event.getRevision() % batchSize != 0 || event.getRevision() == 0) {
189 LOGGER.debug(event::getMessage);
190 } else {
191 LOGGER.info("{} ({}% done)", event.getMessage(),
192 (int) (event.getRevision() * 100.0 / latestRevision));
193 }
194 }
195 }
196 });
197 adminClient.doVerify(repositoryRoot);
198 LOGGER.info("Verified SVN repository '{}'.", replURLStr);
199 } catch (Exception e) {
200 throw new MCRPersistenceException("SVN repository contains errors and could not be verified: " + replURLStr,
201 e);
202 }
203 }
204
205 @Override
206 public MCRVersionedMetadata create(MCRContent xml, int id) throws IOException, JDOMException {
207 return (MCRVersionedMetadata) super.create(xml, id);
208 }
209
210 @Override
211 public MCRVersionedMetadata create(MCRContent xml) throws IOException, JDOMException {
212 return (MCRVersionedMetadata) super.create(xml);
213 }
214
215
216
217
218
219
220
221
222
223
224
225 @Override
226 public MCRVersionedMetadata retrieve(int id) throws IOException {
227 MCRVersionedMetadata metadata = (MCRVersionedMetadata) super.retrieve(id);
228 if (metadata != null) {
229 return metadata;
230 }
231 return new MCRVersionedMetadata(this, getSlot(id), id, super.forceDocType, true);
232 }
233
234
235
236
237 public void updateAll() throws Exception {
238 for (Iterator<Integer> ids = listIDs(true); ids.hasNext();) {
239 retrieve(ids.next()).update();
240 }
241 }
242
243 @Override
244 public void delete(int id) throws IOException {
245 String commitMsg = "Deleted metadata object " + getID() + "_" + id + " in store";
246
247 SVNCommitInfo info;
248 try {
249 SVNRepository repository = getRepository();
250 ISVNEditor editor = repository.getCommitEditor(commitMsg, null);
251 editor.openRoot(-1);
252 editor.deleteEntry("/" + getSlotPath(id), -1);
253 editor.closeDir();
254
255 info = editor.closeEdit();
256 LOGGER.info("SVN commit of delete finished, new revision {}", info.getNewRevision());
257 } catch (SVNException e) {
258 LOGGER.error("Error while deleting {} in SVN ", id, e);
259 } finally {
260 super.delete(id);
261 }
262 }
263
264 @Override
265 protected MCRVersionedMetadata buildMetadataObject(Path fo, int id) {
266 return new MCRVersionedMetadata(this, fo, id, super.forceDocType, false);
267 }
268
269 }