You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2023/09/19 11:18:58 UTC
[commons-vfs] branch master updated: VFS-841: copying Jackrabbit standalone Main class not to depend on wh… (#409)
This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-vfs.git
The following commit(s) were added to refs/heads/master by this push:
new 16b16c39 VFS-841: copying Jackrabbit standalone Main class not to depend on wh… (#409)
16b16c39 is described below
commit 16b16c39c1378b262044f91a90e520fd17d59e86
Author: Woonsan Ko <wo...@users.noreply.github.com>
AuthorDate: Tue Sep 19 20:18:53 2023 +0900
VFS-841: copying Jackrabbit standalone Main class not to depend on wh… (#409)
* VFS-841: copying Jackrabbit standalone Main class not to depend on what's not supposed to be exposed by Jackrabbit2
* VFS-841: extract constants to snooze checkstyle complaints
* Update Webdav4ProviderTestCase.java
---------
Co-authored-by: Gary Gregory <ga...@users.noreply.github.com>
---
.../vfs2/provider/webdav4/test/JackrabbitMain.java | 332 +++++++++++++++++++++
.../webdav4/test/Webdav4ProviderTestCase.java | 8 +-
.../org/apache/commons/vfs2/util/URIUtils.java | 12 +-
3 files changed, 345 insertions(+), 7 deletions(-)
diff --git a/commons-vfs2-jackrabbit2/src/test/java/org/apache/commons/vfs2/provider/webdav4/test/JackrabbitMain.java b/commons-vfs2-jackrabbit2/src/test/java/org/apache/commons/vfs2/provider/webdav4/test/JackrabbitMain.java
new file mode 100644
index 00000000..93e3ee64
--- /dev/null
+++ b/commons-vfs2-jackrabbit2/src/test/java/org/apache/commons/vfs2/provider/webdav4/test/JackrabbitMain.java
@@ -0,0 +1,332 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.
+ */
+
+// COPIED FROM JACKRABBIT 2.20.11 (No additional NOTICE required, see VFS-841)
+
+package org.apache.commons.vfs2.provider.webdav4.test;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.chain.Context;
+import org.apache.commons.chain.impl.ContextBase;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.commons.JcrUtils;
+import org.apache.jackrabbit.core.RepositoryCopier;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.apache.jackrabbit.servlet.jackrabbit.JackrabbitRepositoryServlet;
+import org.apache.jackrabbit.standalone.Main;
+import org.apache.jackrabbit.standalone.cli.CommandException;
+import org.apache.jackrabbit.standalone.cli.CommandHelper;
+import org.apache.jackrabbit.standalone.cli.JcrClient;
+import org.eclipse.jetty.server.NCSARequestLog;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.handler.RequestLogHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+/**
+ * For testing purpose, copied from org.apache.jackrabbit.standalone.Main with renaming the classname,
+ * except of the part calling <CODE>Main.class.getProtectionDomain().getCodeSource().getLocation()</CODE>,
+ * which reads some files from the jackrabbit-standalone-component.jar file directly.
+ */
+public class JackrabbitMain {
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) throws Exception {
+ new JackrabbitMain(args).run();
+ }
+
+ private final Options options = new Options();
+
+ private final CommandLine command;
+
+ private final RequestLogHandler accessLog = new RequestLogHandler();
+
+ private final WebAppContext webapp = new WebAppContext();
+
+ private final Server server = new Server();
+
+ private final ServerConnector connector = new ServerConnector(server);
+
+ /**
+ * Construct Main application instance.
+ * <P>
+ * <EM>Note:</EM> Constructor is protected because other projects such as Commons VFS can extend this for some reasons
+ * (e.g, unit testing against Jackrabbit WebDAV).
+ */
+ protected JackrabbitMain(String[] args) throws ParseException {
+ options.addOption("?", "help", false, "print this message");
+ options.addOption("n", "notice", false, "print copyright notices");
+ options.addOption("l", "license", false, "print license information");
+ options.addOption(
+ "b", "backup", false, "create a backup of the repository");
+ options.addOption(
+ "i", "cli", true, "command line access to a remote repository");
+
+ options.addOption("q", "quiet", false, "disable console output");
+ options.addOption("d", "debug", false, "enable debug logging");
+
+ options.addOption("h", "host", true, "IP address of the HTTP server");
+ options.addOption("p", "port", true, "TCP port of the HTTP server (8080)");
+ options.addOption("f", "file", true, "location of this jar file");
+ options.addOption("r", "repo", true, "repository directory (jackrabbit)");
+ options.addOption("c", "conf", true, "repository configuration file");
+ options.addOption(
+ "R", "backup-repo", true,
+ "backup repository directory (jackrabbit-backupN)");
+ options.addOption(
+ "C", "backup-conf", true,
+ "backup repository configuration file");
+
+ command = new DefaultParser().parse(options, args);
+ }
+
+ /**
+ * Run this Main application.
+ * <P>
+ * <EM>Note:</EM> this is public because this can be used by other projects in unit tests. e.g, Commons-VFS.
+ * @throws Exception if any exception occurs
+ */
+ public void run() throws Exception {
+ String defaultFile = "jackrabbit-standalone.jar";
+ URL location =
+ Main.class.getProtectionDomain().getCodeSource().getLocation();
+ if (location != null && "file".equals(location.getProtocol())) {
+ File file = new File(location.getPath());
+ if (file.isFile()) {
+ defaultFile = location.getPath();
+ }
+ }
+ File file = new File(command.getOptionValue("file", defaultFile));
+
+ if (command.hasOption("help")) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp("java -jar " + file.getName(), options, true);
+ } else if (command.hasOption("notice")) {
+ copyToOutput("/META-INF/NOTICE.txt");
+ } else if (command.hasOption("license")) {
+ copyToOutput("/META-INF/LICENSE.txt");
+ } else if (command.hasOption("cli")) {
+ System.setProperty("logback.configurationFile", "logback-cli.xml");
+
+ String uri = command.getOptionValue("cli");
+ Repository repository = JcrUtils.getRepository(uri);
+
+ Context context = new ContextBase();
+ CommandHelper.setRepository(context, repository, uri);
+ try {
+ Session session = repository.login();
+ CommandHelper.setSession(context, session);
+ CommandHelper.setCurrentNode(context, session.getRootNode());
+ } catch (RepositoryException ignore) {
+ // anonymous login not possible
+ }
+
+ new JcrClient(context).runInteractive();
+
+ try {
+ CommandHelper.getSession(context).logout();
+ } catch (CommandException ignore) {
+ // already logged out
+ }
+ } else {
+ message("Welcome to Apache Jackrabbit!");
+ message("-------------------------------");
+
+ File repository =
+ new File(command.getOptionValue("repo", "jackrabbit"));
+ message("Using repository directory " + repository);
+ repository.mkdirs();
+ File tmp = new File(repository, "tmp");
+ tmp.mkdir();
+ File log = new File(repository, "log");
+ log.mkdir();
+
+ message("Writing log messages to " + log);
+ prepareServerLog(log);
+
+ if (command.hasOption("backup")) {
+ backup(repository);
+ } else {
+ message("Starting the server...");
+ prepareWebapp(file, repository, tmp);
+ accessLog.setHandler(webapp);
+ prepareAccessLog(log);
+ server.setHandler(accessLog);
+ prepareConnector();
+ server.addConnector(connector);
+ prepareShutdown();
+
+ try {
+ server.start();
+
+ String host = connector.getHost();
+ if (host == null) {
+ host = "localhost";
+ }
+ message("Apache Jackrabbit is now running at "
+ +"http://" + host + ":" + connector.getPort() + "/");
+ } catch (Throwable t) {
+ System.err.println(
+ "Unable to start the server: " + t.getMessage());
+ System.exit(1);
+ }
+ }
+ }
+ }
+
+ /**
+ * Shutdown this Main application.
+ * <P>
+ * <EM>Note:</EM> this is public because this can be used by other projects in unit tests for graceful shutdown.
+ * e.g, Commons-VFS. If this is not invoked properly, some unexpected exceptions may occur on shutdown hook
+ * due to an unexpected, invalid state for org.apache.lucene.index.IndexFileDeleter for instance.
+ */
+ public void shutdown() {
+ try {
+ message("Shutting down the server...");
+ server.stop();
+ server.join();
+ message("-------------------------------");
+ message("Goodbye from Apache Jackrabbit!");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void backup(File sourceDir) throws Exception {
+ RepositoryConfig source;
+ if (command.hasOption("conf")) {
+ source = RepositoryConfig.create(
+ new File(command.getOptionValue("conf")), sourceDir);
+ } else {
+ source = RepositoryConfig.create(sourceDir);
+ }
+
+ File targetDir;
+ if (command.hasOption("backup-repo")) {
+ targetDir = new File(command.getOptionValue("backup-repo"));
+ } else {
+ int i = 1;
+ do {
+ targetDir = new File("jackrabbit-backup" + i++);
+ } while (targetDir.exists());
+ }
+
+ RepositoryConfig target;
+ if (command.hasOption("backup-conf")) {
+ target = RepositoryConfig.install(
+ new File(command.getOptionValue("backup-conf")), targetDir);
+ } else {
+ target = RepositoryConfig.install(targetDir);
+ }
+
+ message("Creating a repository copy in " + targetDir);
+ RepositoryCopier.copy(source, target);
+ message("The repository has been successfully copied.");
+ }
+
+ private void prepareServerLog(File log)
+ throws IOException {
+ System.setProperty(
+ "jackrabbit.log", new File(log, "jackrabbit.log").getPath());
+ System.setProperty(
+ "jetty.log", new File(log, "jetty.log").getPath());
+
+ if (command.hasOption("debug")) {
+ System.setProperty("log.level", "DEBUG");
+ } else {
+ System.setProperty("log.level", "INFO");
+ }
+
+ System.setProperty(
+ "derby.stream.error.file",
+ new File(log, "derby.log").getPath());
+ }
+
+ private void prepareAccessLog(File log) {
+ NCSARequestLog ncsa = new NCSARequestLog(
+ new File(log, "access.log.yyyy_mm_dd").getPath());
+ ncsa.setFilenameDateFormat("yyyy-MM-dd");
+ accessLog.setRequestLog(ncsa);
+ }
+
+ private void prepareWebapp(File file, File repository, File tmp) {
+ webapp.setContextPath("/");
+ webapp.setWar(file.getPath());
+ webapp.setExtractWAR(true);
+ webapp.setTempDirectory(tmp);
+
+ ServletHolder servlet =
+ new ServletHolder(JackrabbitRepositoryServlet.class);
+ servlet.setInitOrder(1);
+ servlet.setInitParameter("repository.home", repository.getPath());
+ String conf = command.getOptionValue("conf");
+ if (conf != null) {
+ servlet.setInitParameter("repository.config", conf);
+ }
+ webapp.addServlet(servlet, "/repository.properties");
+ }
+
+ private void prepareConnector() {
+ String port = command.getOptionValue("port", "8080");
+ connector.setPort(Integer.parseInt(port));
+ String host = command.getOptionValue("host");
+ if (host != null) {
+ connector.setHost(host);
+ }
+ }
+
+ private void prepareShutdown() {
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ public void run() {
+ shutdown();
+ }
+ });
+ }
+
+ private void message(String message) {
+ if (!command.hasOption("quiet")) {
+ System.out.println(message);
+ }
+ }
+
+ private void copyToOutput(String resource) throws IOException {
+ InputStream stream = JackrabbitMain.class.getResourceAsStream(resource);
+ try {
+ IOUtils.copy(stream, System.out);
+ } finally {
+ stream.close();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/commons-vfs2-jackrabbit2/src/test/java/org/apache/commons/vfs2/provider/webdav4/test/Webdav4ProviderTestCase.java b/commons-vfs2-jackrabbit2/src/test/java/org/apache/commons/vfs2/provider/webdav4/test/Webdav4ProviderTestCase.java
index 2518b895..93fa66d6 100644
--- a/commons-vfs2-jackrabbit2/src/test/java/org/apache/commons/vfs2/provider/webdav4/test/Webdav4ProviderTestCase.java
+++ b/commons-vfs2-jackrabbit2/src/test/java/org/apache/commons/vfs2/provider/webdav4/test/Webdav4ProviderTestCase.java
@@ -47,12 +47,12 @@ import org.apache.commons.vfs2.provider.webdav4.Webdav4FileProvider;
import org.apache.commons.vfs2.provider.webdav4.Webdav4FileSystemConfigBuilder;
import org.apache.commons.vfs2.util.FreeSocketPortUtil;
import org.apache.jackrabbit.core.TransientRepository;
-import org.apache.jackrabbit.standalone.Main;
import junit.framework.Test;
/**
* Test cases for the WebDAV4 provider.
+ * Do NOT use org.apache.jackrabbit.standalone.Main.
*
* @since 2.5.0
*/
@@ -68,7 +68,7 @@ public class Webdav4ProviderTestCase extends AbstractProviderTestConfig {
private static final String TEST_URI = "test.webdav4.uri";
- private static Main jrMain;
+ private static JackrabbitMain jrMain;
/**
* Use %40 for @ in URLs
@@ -212,7 +212,7 @@ public class Webdav4ProviderTestCase extends AbstractProviderTestConfig {
dump(RepoDirectory);
// Start server with temp repo
startJackrabbit(RepoDirectory);
- message("Returned from org.apache.jackrabbit.standalone.Main " + SocketPort);
+ message("Returned from " + JackrabbitMain.class.getName() + " " + SocketPort);
}
/**
@@ -228,7 +228,7 @@ public class Webdav4ProviderTestCase extends AbstractProviderTestConfig {
quiet = true;
}
- jrMain = new Main(new String[] { "--port", Integer.toString(SocketPort), "--repo", repoDirectory.toString(),
+ jrMain = new JackrabbitMain(new String[] { "--port", Integer.toString(SocketPort), "--repo", repoDirectory.toString(),
quiet ? "--quiet" : "" }) {
};
diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/util/URIUtils.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/util/URIUtils.java
index 5999b8d6..df529a79 100644
--- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/util/URIUtils.java
+++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/util/URIUtils.java
@@ -107,6 +107,12 @@ public class URIUtils {
private static final byte ESCAPE_CHAR = '%';
+ private static final int EIGHT_BIT_CHARSET_SIZE = 256;
+
+ private static final int FOUR_BITS = 4;
+
+ private static final int UNSIGNED_BYTE_MASK = 0xF;
+
// @formatter:off
private static final FluentBitSet WWW_FORM_URL_SAFE = URIBitSets.bitSet()
// alpha characters
@@ -140,7 +146,7 @@ public class URIUtils {
for (final byte c : bytes) {
int b = c;
if (b < 0) {
- b = 256 + b;
+ b = EIGHT_BIT_CHARSET_SIZE + b;
}
if (urlsafe.get(b)) {
if (b == ' ') {
@@ -149,7 +155,7 @@ public class URIUtils {
buffer.write(b);
} else {
buffer.write(ESCAPE_CHAR);
- final char hex1 = hexDigit(b >> 4);
+ final char hex1 = hexDigit(b >> FOUR_BITS);
final char hex2 = hexDigit(b);
buffer.write(hex1);
buffer.write(hex2);
@@ -159,7 +165,7 @@ public class URIUtils {
}
private static char hexDigit(final int b) {
- return Character.toUpperCase(Character.forDigit(b & 0xF, RADIX));
+ return Character.toUpperCase(Character.forDigit(b & UNSIGNED_BYTE_MASK, RADIX));
}
}