[spring-extensions] branch master updated: IDP-1172 Deprecate SVNResource
Rod Widdowson
rdw at steadingsoftware.com
Mon Aug 7 07:51:08 EDT 2017
This is an automated email from the git hooks/post-receive script.
rdw pushed a commit to branch master
in repository spring-extensions.
View the commit online:
http://git.shibboleth.net/view/?p=spring-extensions.git;a=commit;h=b67b6199d4f4381a25f1c47033deb7baf91675e5
The following commit(s) were added to refs/heads/master by this push:
new b67b619 IDP-1172 Deprecate SVNResource
b67b619 is described below
commit b67b6199d4f4381a25f1c47033deb7baf91675e5
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Mon Aug 7 12:49:45 2017 +0100
IDP-1172 Deprecate SVNResource
https://issues.shibboleth.net/jira/browse/IDP-1172
To provide an example, code up (in the test tree) an SVNRunnable
---
.../resource/SVNBasicAuthenticationManager.java | 9 +-
.../ext/spring/resource/SVNResource.java | 12 +-
.../ext/spring/resource/SVNResourceTest.java | 5 +-
.../ext/spring/resource/SVNRunnable.java | 277 +++++++++++++++++++++
.../{SVNResourceTest.java => SVNRunnableTest.java} | 38 +--
5 files changed, 314 insertions(+), 27 deletions(-)
diff --git a/src/main/java/net/shibboleth/ext/spring/resource/SVNBasicAuthenticationManager.java b/src/main/java/net/shibboleth/ext/spring/resource/SVNBasicAuthenticationManager.java
index 328da19..c02207a 100644
--- a/src/main/java/net/shibboleth/ext/spring/resource/SVNBasicAuthenticationManager.java
+++ b/src/main/java/net/shibboleth/ext/spring/resource/SVNBasicAuthenticationManager.java
@@ -22,12 +22,14 @@ import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
-import net.shibboleth.utilities.java.support.annotation.ParameterName;
-
import org.springframework.beans.factory.InitializingBean;
import org.tmatesoft.svn.core.auth.BasicAuthenticationManager;
import org.tmatesoft.svn.core.auth.SVNAuthentication;
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.primitive.DeprecationSupport;
+import net.shibboleth.utilities.java.support.primitive.DeprecationSupport.ObjectType;
+
/**
* Authentication manager for SVN resources based on {@link BasicAuthenticationManager}. <br/>
* Exbeds the proxy information into individual beans to allow setting from Spring.
@@ -67,13 +69,14 @@ public class SVNBasicAuthenticationManager extends BasicAuthenticationManager im
* @param passphrase a password to the private key
* @param portNumber a port number over which an ssh tunnel is established
*/
- @SuppressWarnings("deprecation")
+ @Deprecated
public SVNBasicAuthenticationManager(
@ParameterName(name="userName") final String userName,
@ParameterName(name="keyFile" ) final File keyFile,
@ParameterName(name="passphrase") final String passphrase,
@ParameterName(name="portNumber") final int portNumber) {
super(userName, keyFile, passphrase, portNumber);
+ DeprecationSupport.warnOnce(ObjectType.CLASS, SVNBasicAuthenticationManager.class.getName(), null, null);
}
/**
diff --git a/src/main/java/net/shibboleth/ext/spring/resource/SVNResource.java b/src/main/java/net/shibboleth/ext/spring/resource/SVNResource.java
index 25be902..b63b579 100644
--- a/src/main/java/net/shibboleth/ext/spring/resource/SVNResource.java
+++ b/src/main/java/net/shibboleth/ext/spring/resource/SVNResource.java
@@ -27,10 +27,6 @@ import java.net.URL;
import javax.annotation.Nonnull;
-import net.shibboleth.utilities.java.support.annotation.ParameterName;
-import net.shibboleth.utilities.java.support.component.AbstractIdentifiedInitializableComponent;
-import net.shibboleth.utilities.java.support.primitive.StringSupport;
-
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,6 +45,12 @@ import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNStatus;
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.component.AbstractIdentifiedInitializableComponent;
+import net.shibboleth.utilities.java.support.primitive.DeprecationSupport;
+import net.shibboleth.utilities.java.support.primitive.DeprecationSupport.ObjectType;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
/**
* Implementation of a Spring {@link Resource} that communications with a Subversion server (via a spool directory).
*
@@ -63,6 +65,7 @@ import org.tmatesoft.svn.core.wc.SVNStatus;
*
* The behavior of multiple {@link SVNResource} operating on the same local copy are undefined.
*/
+ at Deprecated
public class SVNResource extends AbstractIdentifiedInitializableComponent implements Resource, BeanNameAware,
InitializingBean, net.shibboleth.utilities.java.support.resource.Resource {
@@ -104,6 +107,7 @@ public class SVNResource extends AbstractIdentifiedInitializableComponent implem
@Nonnull @ParameterName(name="workingCopy") final File workingCopy,
@ParameterName(name="workingRevision") final long workingRevision,
@Nonnull @ParameterName(name="resourceFile") final String resourceFile) {
+ DeprecationSupport.warnOnce(ObjectType.CLASS, SVNResource.class.getName(), null, null);
DAVRepositoryFactory.setup();
SVNRepositoryFactoryImpl.setup();
FSRepositoryFactory.setup();
diff --git a/src/test/java/net/shibboleth/ext/spring/resource/SVNResourceTest.java b/src/test/java/net/shibboleth/ext/spring/resource/SVNResourceTest.java
index fa3fc1f..4afa6e2 100644
--- a/src/test/java/net/shibboleth/ext/spring/resource/SVNResourceTest.java
+++ b/src/test/java/net/shibboleth/ext/spring/resource/SVNResourceTest.java
@@ -24,8 +24,6 @@ import java.nio.file.Path;
import java.text.ParseException;
import java.util.Collection;
-import net.shibboleth.ext.spring.util.SchemaTypeAwareXMLBeanDefinitionReader;
-
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
@@ -48,9 +46,12 @@ import org.tmatesoft.svn.core.auth.BasicAuthenticationManager;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.wc.SVNClientManager;
+import net.shibboleth.ext.spring.util.SchemaTypeAwareXMLBeanDefinitionReader;
+
/**
* test,
*/
+ at SuppressWarnings("deprecation")
public class SVNResourceTest {
static private final String ORIGINAL_TEXT = "This is a Test Resource which will be superseded by other Data";
diff --git a/src/test/java/net/shibboleth/ext/spring/resource/SVNRunnable.java b/src/test/java/net/shibboleth/ext/spring/resource/SVNRunnable.java
new file mode 100644
index 0000000..0a0d9ba
--- /dev/null
+++ b/src/test/java/net/shibboleth/ext/spring/resource/SVNRunnable.java
@@ -0,0 +1,277 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.ext.spring.resource;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.annotation.Nonnull;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.BeanCreationException;
+import org.springframework.beans.factory.BeanNameAware;
+import org.springframework.beans.factory.InitializingBean;
+import org.tmatesoft.svn.core.SVNDepth;
+import org.tmatesoft.svn.core.SVNException;
+import org.tmatesoft.svn.core.SVNURL;
+import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
+import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
+import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
+import org.tmatesoft.svn.core.wc.SVNClientManager;
+import org.tmatesoft.svn.core.wc.SVNRevision;
+
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.component.AbstractIdentifiedInitializableComponent;
+
+/**
+ * Implementation of a {@link Runnable} that communications with a Subversion server (via a spool directory).
+ *
+ */
+public class SVNRunnable extends AbstractIdentifiedInitializableComponent
+ implements Runnable, BeanNameAware, InitializingBean {
+
+ /** Class logger. */
+ private final Logger log = LoggerFactory.getLogger(SVNRunnable.class);
+
+ /** SVN Client manager. */
+ @Nonnull private final SVNClientManager clientManager;
+
+ /** URL to the remote repository. */
+ @Nonnull private SVNURL remoteRepository;
+
+ /** Directory where the working copy will be kept. */
+ @Nonnull private File workingCopyDirectory;
+
+ /** Revision of the working copy. */
+ private SVNRevision retrievalRevision;
+
+ /**
+ * Constructor.
+ *
+ * @param svnClientMgr manager used to create SVN clients
+ * @param repositoryUrl URL of the remote repository
+ * @param workingCopy directory that will serve as the root of the local working copy
+ * @param workingRevision revision of the resource to retrieve or -1 for HEAD revision
+ * @param resourceFile file, within the working copy, represented by this resource
+ *
+ * @throws BeanCreationException thrown if there is a problem initializing the SVN resource
+ */
+ public SVNRunnable(@Nonnull @ParameterName(name = "svnClientMgr") final SVNClientManager svnClientMgr,
+ @Nonnull @ParameterName(name = "repositoryUrl") final SVNURL repositoryUrl,
+ @Nonnull @ParameterName(name = "workingCopy") final File workingCopy,
+ @ParameterName(name = "workingRevision") final long workingRevision) {
+
+ DAVRepositoryFactory.setup();
+ SVNRepositoryFactoryImpl.setup();
+ FSRepositoryFactory.setup();
+ if (svnClientMgr == null) {
+ log.error("SVN client manager may not be null");
+ throw new BeanCreationException("SVN client manager may not be null");
+ }
+ clientManager = svnClientMgr;
+
+ if (repositoryUrl == null) {
+ throw new BeanCreationException("SVN repository URL may not be null");
+ }
+ remoteRepository = repositoryUrl;
+
+ try {
+ checkWorkingCopyDirectory(workingCopy);
+ workingCopyDirectory = workingCopy;
+ } catch (final IOException e) {
+ throw new BeanCreationException(e.getMessage());
+ }
+
+ if (workingRevision < 0) {
+ this.retrievalRevision = SVNRevision.HEAD;
+ } else {
+ this.retrievalRevision = SVNRevision.create(workingRevision);
+ }
+
+ try {
+ checkoutOrUpdate();
+ } catch (final IOException e) {
+ throw new BeanCreationException(e.getMessage());
+ }
+ }
+
+ /** Helper function to generate the full path for injecting into URLs and URIs.
+ *
+ * @return the directory path (from svn) pus the file.
+ *
+ * protected String getFullPath() { final StringBuffer buffer = new
+ * StringBuffer(remoteRepository.getPath().length() + 1 + getFilename().length());
+ * buffer.append(remoteRepository.getPath()).append('/').append(getFilename()); return buffer.toString(); }
+ *
+ * /** Helper function to return a complex scheme - a conjunction of 'svn' and the underlying protocol.
+ *
+ * @return 'svn+'protocol
+ */
+ protected String getProtocol() {
+ final StringBuffer buffer = new StringBuffer(4 + remoteRepository.getProtocol().length());
+ buffer.append("svn+").append(remoteRepository.getProtocol());
+ return buffer.toString();
+ }
+
+ /**
+ * Checks that the given file exists, or can be created, is a directory, and is read/writable by this process.
+ *
+ * @param directory the directory to check
+ *
+ * @throws IOException thrown if the file is invalid
+ */
+ protected void checkWorkingCopyDirectory(@Nonnull final File directory) throws IOException {
+ if (directory == null) {
+ log.error("SVN working copy directory cannot be null");
+ throw new IOException("SVN working copy directory cannot be null");
+ }
+
+ if (!directory.exists()) {
+ final boolean created = directory.mkdirs();
+ if (!created) {
+ final String msg = "SVN working copy directory " + directory.getAbsolutePath()
+ + " does not exist and could not be created";
+ log.error(msg);
+ throw new IOException(msg);
+ }
+ }
+
+ if (!directory.isDirectory()) {
+ final String msg = "SVN working copy location " + directory.getAbsolutePath() + " is not a directory";
+ log.error(msg);
+ throw new IOException(msg);
+ }
+
+ if (!directory.canRead()) {
+ final String msg =
+ "SVN working copy directory " + directory.getAbsolutePath() + " cannot be read by this process";
+ log.error(msg);
+ throw new IOException(msg);
+ }
+
+ if (!directory.canWrite()) {
+ final String msg = "SVN working copy directory " + directory.getAbsolutePath()
+ + " cannot be written to by this process";
+ log.error(msg);
+ throw new IOException(msg);
+ }
+ }
+
+ /**
+ * Checks out the resource specified by the {@link #remoteRepository} in to the working copy
+ * {@link #workingCopyDirectory}. If the working copy is empty than an SVN checkout is performed if the working copy
+ * already exists then an SVN update is performed.
+ *
+ * @throws IOException thrown if there is a problem communicating with the remote repository, the revision does not
+ * exist, or the working copy is unusable
+ */
+ protected void checkoutOrUpdate() throws IOException {
+ log.debug("checking out or updating working copy");
+
+ if (!workingCopyDirectoryExists()) {
+ log.debug("Working copy does not yet exist, checking it out to {}", workingCopyDirectory.getAbsolutePath());
+ checkoutResourceDirectory();
+ } else {
+ if (retrievalRevision != SVNRevision.HEAD) {
+ log.debug("Working copy exists and version is pegged at {}, no need to update",
+ retrievalRevision.toString());
+ return;
+ }
+ log.debug("Working copy exists, updating to latest version.");
+ updateResourceDirectory();
+ }
+ }
+
+ /**
+ * Checks to see if the working copy directory exists.
+ *
+ * @return true if the working copy directory exists, false otherwise
+ */
+ private boolean workingCopyDirectoryExists() {
+ final File svnMetadataDir = new File(workingCopyDirectory, ".svn");
+ return svnMetadataDir.exists();
+ }
+
+ /**
+ * Fetches the content from the SVN repository and creates the local working copy.
+ *
+ * @return the revision of the fetched content
+ *
+ * @throws IOException thrown if there is a problem checking out the content from the repository
+ */
+ private SVNRevision checkoutResourceDirectory() throws IOException {
+ try {
+ final long newRevision = clientManager.getUpdateClient().doCheckout(remoteRepository, workingCopyDirectory,
+ retrievalRevision, retrievalRevision, SVNDepth.INFINITY, true);
+ log.debug("Checked out revision {} from remote repository {} and stored it in local working directory {}",
+ new Object[] {newRevision, remoteRepository.toDecodedString(),
+ workingCopyDirectory.getAbsolutePath(),});
+ return SVNRevision.create(newRevision);
+ } catch (final SVNException e) {
+ final String errMsg = "Unable to check out revsion " + retrievalRevision.toString()
+ + " from remote repository " + remoteRepository.toDecodedString() + " to local working directory "
+ + workingCopyDirectory.getAbsolutePath();
+ log.error(errMsg, e);
+ throw new IOException(errMsg, e);
+ }
+ }
+
+ /** Updates an existing local working copy from the repository.
+ *
+ * @return the revision of the fetched content
+ *
+ * @throws IOException thrown if there is a problem updating the working copy
+ */
+ private void updateResourceDirectory() throws IOException {
+ try {
+ final long newRevision = clientManager.getUpdateClient().doUpdate(workingCopyDirectory, retrievalRevision,
+ SVNDepth.INFINITY, true, true);
+ log.debug("Updated local working directory {} to revision {} from remote repository {}", new Object[] {
+ workingCopyDirectory.getAbsolutePath(), newRevision, remoteRepository.toDecodedString(),});
+ } catch (final SVNException e) {
+ final String errMsg = "Unable to update working copy of resoure " + remoteRepository.toDecodedString()
+ + " in working copy " + workingCopyDirectory.getAbsolutePath() + " to revsion "
+ + retrievalRevision.toString();
+ log.error(errMsg, e);
+ throw new IOException(errMsg, e);
+ }
+ }
+
+ @Override public void afterPropertiesSet() throws Exception {
+ initialize();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void setBeanName(final String name) {
+ // For some reason Spring will call this after initialization.
+ if (!isInitialized()) {
+ setId(name);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public void run() {
+ try {
+ checkoutOrUpdate();
+ } catch (final IOException e) {
+ log.error("Failed to update", e);
+ }
+ }
+
+}
diff --git a/src/test/java/net/shibboleth/ext/spring/resource/SVNResourceTest.java b/src/test/java/net/shibboleth/ext/spring/resource/SVNRunnableTest.java
similarity index 87%
copy from src/test/java/net/shibboleth/ext/spring/resource/SVNResourceTest.java
copy to src/test/java/net/shibboleth/ext/spring/resource/SVNRunnableTest.java
index fa3fc1f..758fe38 100644
--- a/src/test/java/net/shibboleth/ext/spring/resource/SVNResourceTest.java
+++ b/src/test/java/net/shibboleth/ext/spring/resource/SVNRunnableTest.java
@@ -24,10 +24,6 @@ import java.nio.file.Path;
import java.text.ParseException;
import java.util.Collection;
-import net.shibboleth.ext.spring.util.SchemaTypeAwareXMLBeanDefinitionReader;
-
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
@@ -48,10 +44,12 @@ import org.tmatesoft.svn.core.auth.BasicAuthenticationManager;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.wc.SVNClientManager;
+import net.shibboleth.ext.spring.util.SchemaTypeAwareXMLBeanDefinitionReader;
+
/**
* test,
*/
-public class SVNResourceTest {
+public class SVNRunnableTest {
static private final String ORIGINAL_TEXT = "This is a Test Resource which will be superseded by other Data";
@@ -82,7 +80,7 @@ public class SVNResourceTest {
}
@BeforeMethod public void makeDir() throws IOException {
- final Path p = Files.createTempDirectory("SVNResourceTest");
+ final Path p = Files.createTempDirectory("SVNRunnableTest");
theDir = p.toFile();
}
@@ -100,15 +98,24 @@ public class SVNResourceTest {
theDir.delete();
theDir = null;
}
+
+ private Resource makeResource(
+ final SVNClientManager svnClientMgr,
+ final SVNURL repositoryUrl,
+ final File workingCopy,
+ final long workingRevision,
+ final String resourceFile)
+ {
+ final SVNRunnable runnable = new SVNRunnable(svnClientMgr, repositoryUrl, workingCopy, workingRevision);
+
+ return new RunnableFileSystemResource(new File(workingCopy, resourceFile), runnable);
+ }
+
@Test(enabled=true) public void testRevision() throws IOException, ParseException {
- final Resource resource = new SVNResource(clientManager, url, theDir, ORIGINAL_VERSION, FILENAME);
+ final Resource resource = makeResource(clientManager, url, theDir, ORIGINAL_VERSION, FILENAME);
Assert.assertTrue(resource.exists());
- final long delta =
- resource.lastModified() - new DateTime(2017, 3, 20, 13, 40, 50, 500, DateTimeZone.UTC).getMillis();
- Assert.assertTrue(delta < 501 && delta > -501);
-
final Resource other = new ByteArrayResource(ORIGINAL_TEXT.getBytes());
Assert.assertTrue(ResourceTestHelper.compare(other, resource));
@@ -118,20 +125,15 @@ public class SVNResourceTest {
}
@Test(enabled=true) public void testNotExist() {
- final Resource resource = new SVNResource(clientManager, url, theDir, 0, FILENAME);
+ final Resource resource = makeResource(clientManager, url, theDir, 0, FILENAME);
Assert.assertFalse(resource.exists());
}
@Test(enabled=true) public void testMain() throws IOException {
- final Resource resource = new SVNResource(clientManager, url, theDir, -1, FILENAME);
+ final Resource resource = makeResource(clientManager, url, theDir, -1, FILENAME);
Assert.assertTrue(resource.exists());
- // CHANGE IF WE CHECKIN A NEW FILE
- final long delta =
- resource.lastModified() - new DateTime(2017, 3, 20, 13, 41, 26, 500, DateTimeZone.UTC).getMillis();
- Assert.assertTrue(delta < 501 && delta > -501);
-
Assert.assertTrue(ResourceTestHelper.compare(comparer, resource));
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list