-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.argeo.commons</groupId>
<artifactId>argeo-cli</artifactId>
<packaging>pom</packaging>
<name>Argeo Command Line</name>
+ <properties>
+ <graalvm.version>20.0.0</graalvm.version>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.dep.cms.client</artifactId>
+ <version>2.1.89-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.dep.cms.node</artifactId>
+ <version>2.1.89-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
<profiles>
<profile>
<id>dist</id>
- <dependencies>
- <dependency>
- <groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.dep.cms.client</artifactId>
- <version>2.1.89-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.argeo.commons</groupId>
- <artifactId>org.argeo.dep.cms.node</artifactId>
- <version>2.1.89-SNAPSHOT</version>
- </dependency>
- </dependencies>
<build>
<plugins>
<plugin>
</plugins>
</build>
</profile>
+ <profile>
+ <id>native-image</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.graalvm.nativeimage</groupId>
+ <artifactId>native-image-maven-plugin</artifactId>
+ <version>${graalvm.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>native-image</goal>
+ </goals>
+ <phase>package</phase>
+ </execution>
+ </executions>
+ <configuration>
+ <imageName>argeo</imageName>
+ <mainClass>org.argeo.cms.cli.ArgeoCli</mainClass>
+ <buildArgs>
+ --no-fallback
+ --allow-incomplete-classpath
+ --initialize-at-build-time=org.apache.lucene.util.AttributeImpl,org.apache.lucene.util.VirtualMethod,org.apache.lucene.util.WeakIdentityMap
+ -H:EnableURLProtocols=http,https
+ -H:IncludeResourceBundles=sun.security.util.Resources
+ -H:ConfigurationFileDirectories=${basedir}/native-image
+ -H:ReflectionConfigurationFiles=${basedir}/native-image/reflect-config.json
+ -H:ResourceConfigurationFiles=${basedir}/native-image/resource-config.json
+ -H:JNIConfigurationFiles=${basedir}/native-image/jni-config.json
+ </buildArgs>
+ <skip>false</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.graalvm.sdk</groupId>
+ <artifactId>graal-sdk</artifactId>
+ <version>${graalvm.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ </profile>
</profiles>
</project>
import org.apache.commons.cli.Option;
import org.argeo.cli.CommandsCli;
import org.argeo.cli.fs.FsCommands;
+import org.argeo.cli.jcr.JcrCommands;
import org.argeo.cli.posix.PosixCommands;
/** Argeo command line tools. */
addCommandsCli(new PosixCommands("posix"));
addCommandsCli(new FsCommands("fs"));
+ addCommandsCli(new JcrCommands("jcr"));
}
@Override
package org.argeo.cms.internal.http;
import java.io.Serializable;
+import java.util.LinkedHashMap;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
private final String alias;
-// private LinkedHashMap<Session, CmsSessionImpl> cmsSessions = new LinkedHashMap<>();
+ private LinkedHashMap<Session, CmsSessionImpl> cmsSessions = new LinkedHashMap<>();
public CmsSessionProvider(String alias) {
this.alias = alias;
throws javax.jcr.LoginException, ServletException, RepositoryException {
// a client is scanning parent URLs.
- if (workspace == null)
- return null;
+// if (workspace == null)
+// return null;
CmsSessionImpl cmsSession = WebCmsSessionImpl.getCmsSession(request);
if (log.isTraceEnabled()) {
log.trace("Get JCR session from " + cmsSession);
}
Session session = cmsSession.newDataSession(alias, workspace, rep);
-// cmsSessions.put(session, cmsSession);
+ cmsSessions.put(session, cmsSession);
return session;
}
public void releaseSession(Session session) {
- JcrUtils.logoutQuietly(session);
-// if (cmsSessions.containsKey(session)) {
-// CmsSessionImpl cmsSession = cmsSessions.get(session);
-// cmsSession.releaseDataSession(alias, session);
-// } else {
-// log.warn("JCR session " + session + " not found in CMS session list. Logging it out...");
-// JcrUtils.logoutQuietly(session);
-// }
+// JcrUtils.logoutQuietly(session);
+ if (cmsSessions.containsKey(session)) {
+ CmsSessionImpl cmsSession = cmsSessions.get(session);
+ cmsSession.releaseDataSession(alias, session);
+ } else {
+ log.warn("JCR session " + session + " not found in CMS session list. Logging it out...");
+ JcrUtils.logoutQuietly(session);
+ }
}
}
Import-Package: com.fasterxml.jackson.annotation;resolution:=optional,\
com.fasterxml.jackson.core;resolution:=optional,\
com.fasterxml.jackson.databind;resolution:=optional,\
+ org.apache.jackrabbit.api;resolution:=optional,\
+ org.apache.jackrabbit.commons;resolution:=optional,\
*;resolution:=optional
\ No newline at end of file
bin.includes = META-INF/,\
.
additional.bundles = org.apache.sshd.common,\
+ org.apache.jackrabbit.data,\
org.slf4j.log4j12,\
org.slf4j.api,\
org.apache.sshd.core,\
--- /dev/null
+package org.argeo.cli;
+
+import java.util.List;
+
+/** {@link RuntimeException} referring during a command run. */
+public class CommandRuntimeException extends RuntimeException {
+ private static final long serialVersionUID = 5595999301269377128L;
+
+ private final DescribedCommand<?> command;
+ private final List<String> arguments;
+
+ public CommandRuntimeException(Throwable e, DescribedCommand<?> command, List<String> arguments) {
+ this(null, e, command, arguments);
+ }
+
+ public CommandRuntimeException(String message, DescribedCommand<?> command, List<String> arguments) {
+ this(message, null, command, arguments);
+ }
+
+ public CommandRuntimeException(String message, Throwable e, DescribedCommand<?> command, List<String> arguments) {
+ super(message == null ? "(" + command.getClass().getName() + " " + arguments.toString() + ")"
+ : message + " (" + command.getClass().getName() + " " + arguments.toString() + ")", e);
+ this.command = command;
+ this.arguments = arguments;
+ }
+
+ public DescribedCommand<?> getCommand() {
+ return command;
+ }
+
+ public List<String> getArguments() {
+ return arguments;
+ }
+
+}
--- /dev/null
+package org.argeo.cli.jcr;
+
+import org.argeo.cli.CommandsCli;
+
+/** File utilities. */
+public class JcrCommands extends CommandsCli {
+
+ public JcrCommands(String commandName) {
+ super(commandName);
+ addCommand("sync", new JcrSync());
+ }
+
+ @Override
+ public String getDescription() {
+ return "Utilities around remote and local JCR repositories";
+ }
+
+}
--- /dev/null
+package org.argeo.cli.jcr;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Credentials;
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.RepositoryFactory;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.jackrabbit.core.RepositoryImpl;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.argeo.cli.CommandArgsException;
+import org.argeo.cli.CommandRuntimeException;
+import org.argeo.cli.DescribedCommand;
+import org.argeo.jackrabbit.client.ClientDavexRepositoryFactory;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.sync.SyncResult;
+
+public class JcrSync implements DescribedCommand<SyncResult<Node>> {
+ public final static String DEFAULT_LOCALFS_CONFIG = "repository-localfs.xml";
+
+ final static Option deleteOption = Option.builder().longOpt("delete").desc("delete from target").build();
+ final static Option recursiveOption = Option.builder("r").longOpt("recursive").desc("recurse into directories")
+ .build();
+ final static Option progressOption = Option.builder().longOpt("progress").hasArg(false).desc("show progress")
+ .build();
+
+ @Override
+ public SyncResult<Node> apply(List<String> t) {
+ try {
+ CommandLine line = toCommandLine(t);
+ List<String> remaining = line.getArgList();
+ if (remaining.size() == 0) {
+ throw new CommandArgsException("There must be at least one argument");
+ }
+ URI sourceUri = new URI(remaining.get(0));
+ URI targetUri;
+ if (remaining.size() == 1) {
+ targetUri = Paths.get(System.getProperty("user.dir")).toUri();
+ } else {
+ targetUri = new URI(remaining.get(1));
+ }
+ boolean delete = line.hasOption(deleteOption.getLongOpt());
+ boolean recursive = line.hasOption(recursiveOption.getLongOpt());
+
+ // TODO make it configurable
+ String sourceWorkspace = "home";
+ String targetWorkspace = sourceWorkspace;
+
+ final Repository sourceRepository;
+ final Session sourceSession;
+ Credentials sourceCredentials = null;
+ final Repository targetRepository;
+ final Session targetSession;
+ Credentials targetCredentials = null;
+
+ if ("http".equals(sourceUri.getScheme()) || "https".equals(sourceUri.getScheme())) {
+ sourceRepository = createRemoteRepository(sourceUri);
+ } else if (null == sourceUri.getScheme() || "file".equals(sourceUri.getScheme())) {
+ RepositoryConfig repositoryConfig = RepositoryConfig.create(
+ JcrSync.class.getResourceAsStream(DEFAULT_LOCALFS_CONFIG), sourceUri.getPath().toString());
+ sourceRepository = RepositoryImpl.create(repositoryConfig);
+ sourceCredentials = new SimpleCredentials("admin", "admin".toCharArray());
+ } else {
+ throw new IllegalArgumentException("Unsupported scheme " + sourceUri.getScheme());
+ }
+ sourceSession = JcrUtils.loginOrCreateWorkspace(sourceRepository, sourceWorkspace, sourceCredentials);
+
+ if ("http".equals(targetUri.getScheme()) || "https".equals(targetUri.getScheme())) {
+ targetRepository = createRemoteRepository(targetUri);
+ } else if (null == targetUri.getScheme() || "file".equals(targetUri.getScheme())) {
+ RepositoryConfig repositoryConfig = RepositoryConfig.create(
+ JcrSync.class.getResourceAsStream(DEFAULT_LOCALFS_CONFIG), targetUri.getPath().toString());
+ targetRepository = RepositoryImpl.create(repositoryConfig);
+ targetCredentials = new SimpleCredentials("admin", "admin".toCharArray());
+ } else {
+ throw new IllegalArgumentException("Unsupported scheme " + targetUri.getScheme());
+ }
+ targetSession = JcrUtils.loginOrCreateWorkspace(targetRepository, targetWorkspace, targetCredentials);
+
+ JcrUtils.copy(sourceSession.getRootNode(), targetSession.getRootNode());
+ return new SyncResult<Node>();
+ } catch (URISyntaxException e) {
+ throw new CommandArgsException(e);
+ } catch (Exception e) {
+ throw new CommandRuntimeException(e, this, t);
+ }
+ }
+
+ protected Repository createRemoteRepository(URI uri) throws RepositoryException {
+ RepositoryFactory repositoryFactory = new ClientDavexRepositoryFactory();
+ Map<String, String> params = new HashMap<String, String>();
+ params.put(ClientDavexRepositoryFactory.JACKRABBIT_DAVEX_URI, uri.toString());
+ params.put(ClientDavexRepositoryFactory.JACKRABBIT_REMOTE_DEFAULT_WORKSPACE, "main");
+ return repositoryFactory.getRepository(params);
+ }
+
+ @Override
+ public Options getOptions() {
+ Options options = new Options();
+ options.addOption(recursiveOption);
+ options.addOption(deleteOption);
+ options.addOption(progressOption);
+ return options;
+ }
+
+ @Override
+ public String getUsage() {
+ return "[source URI] [target URI]";
+ }
+
+ public static void main(String[] args) {
+ DescribedCommand.mainImpl(new JcrSync(), args);
+ }
+
+ @Override
+ public String getDescription() {
+ return "Synchronises JCR repositories";
+ }
+
+}
--- /dev/null
+/** JCR CLI commands. */
+package org.argeo.cli.jcr;
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<!--
+
+ Copyright (C) 2007-2012 Argeo GmbH
+
+ Licensed 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.
+
+-->
+<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 1.6//EN"
+ "http://jackrabbit.apache.org/dtd/repository-2.0.dtd">
+<Repository>
+ <!-- File system and datastore -->
+ <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+ <param name="path" value="${rep.home}/repository" />
+ </FileSystem>
+ <DataStore class="org.apache.jackrabbit.core.data.FileDataStore">
+ <param name="path" value="${rep.home}/datastore" />
+ </DataStore>
+
+ <!-- Workspace templates -->
+ <Workspaces rootPath="${rep.home}/workspaces"
+ defaultWorkspace="main" configRootPath="/workspaces" />
+ <Workspace name="${wsp.name}">
+ <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+ <param name="path" value="${wsp.home}" />
+ </FileSystem>
+ <PersistenceManager
+ class="org.apache.jackrabbit.core.persistence.bundle.BundleFsPersistenceManager">
+ <param name="blobFSBlockSize" value="1" />
+ </PersistenceManager>
+ <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+ <param name="path" value="${rep.home}/repository/index" />
+ </SearchIndex>
+ </Workspace>
+
+ <!-- Versioning -->
+ <Versioning rootPath="${rep.home}/version">
+ <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+ <param name="path" value="${rep.home}/version" />
+ </FileSystem>
+ <PersistenceManager
+ class="org.apache.jackrabbit.core.persistence.bundle.BundleFsPersistenceManager">
+ <param name="blobFSBlockSize" value="1" />
+ </PersistenceManager>
+ </Versioning>
+
+ <!-- Indexing -->
+ <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+ <param name="path" value="${rep.home}/repository/index" />
+ <param name="tikaConfigPath" value="tika-config.xml"/>
+ </SearchIndex>
+
+ <!-- Security -->
+ <Security appName="Jackrabbit">
+ <SecurityManager
+ class="org.apache.jackrabbit.core.security.simple.SimpleSecurityManager"
+ workspaceName="security" />
+ <AccessManager
+ class="org.apache.jackrabbit.core.security.simple.SimpleAccessManager" />
+ <LoginModule
+ class="org.apache.jackrabbit.core.security.simple.SimpleLoginModule">
+ <param name="anonymousId" value="anonymous" />
+ <param name="adminId" value="admin" />
+ </LoginModule>
+ </Security>
+</Repository>
\ No newline at end of file
--- /dev/null
+package org.argeo.jackrabbit.client;
+
+import java.util.Map;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.RepositoryFactory;
+
+import org.apache.jackrabbit.jcr2spi.Jcr2spiRepositoryFactory;
+import org.apache.jackrabbit.jcr2spi.RepositoryImpl;
+import org.apache.jackrabbit.spi.RepositoryServiceFactory;
+
+/** A customised {@link RepositoryFactory} access a remote DAVEX service. */
+public class ClientDavexRepositoryFactory implements RepositoryFactory {
+ public final static String JACKRABBIT_DAVEX_URI = ClientDavexRepositoryServiceFactory.PARAM_REPOSITORY_URI;
+ public final static String JACKRABBIT_REMOTE_DEFAULT_WORKSPACE = ClientDavexRepositoryServiceFactory.PARAM_WORKSPACE_NAME_DEFAULT;
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public Repository getRepository(Map parameters) throws RepositoryException {
+ RepositoryServiceFactory repositoryServiceFactory = new ClientDavexRepositoryServiceFactory();
+ return RepositoryImpl
+ .create(new Jcr2spiRepositoryFactory.RepositoryConfigImpl(repositoryServiceFactory, parameters));
+ }
+
+}
--- /dev/null
+package org.argeo.jackrabbit.client;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.jackrabbit.spi.SessionInfo;
+import org.apache.jackrabbit.spi2davex.BatchReadConfig;
+import org.apache.jackrabbit.spi2davex.RepositoryServiceImpl;
+
+/**
+ * Wrapper for {@link RepositoryServiceImpl} in order to access the underlying
+ * {@link HttpClientContext}.
+ */
+public class ClientDavexRepositoryService extends RepositoryServiceImpl {
+
+ public ClientDavexRepositoryService(String jcrServerURI, BatchReadConfig batchReadConfig)
+ throws RepositoryException {
+ super(jcrServerURI, batchReadConfig);
+ }
+
+ public ClientDavexRepositoryService(String jcrServerURI, String defaultWorkspaceName,
+ BatchReadConfig batchReadConfig, int itemInfoCacheSize, int maximumHttpConnections)
+ throws RepositoryException {
+ super(jcrServerURI, defaultWorkspaceName, batchReadConfig, itemInfoCacheSize, maximumHttpConnections);
+ }
+
+ public ClientDavexRepositoryService(String jcrServerURI, String defaultWorkspaceName,
+ BatchReadConfig batchReadConfig, int itemInfoCacheSize) throws RepositoryException {
+ super(jcrServerURI, defaultWorkspaceName, batchReadConfig, itemInfoCacheSize);
+ }
+
+ @Override
+ protected HttpContext getContext(SessionInfo sessionInfo) throws RepositoryException {
+ HttpClientContext result = HttpClientContext.create();
+ result.setAuthCache(new NonSerialBasicAuthCache());
+ return result;
+ }
+
+}
--- /dev/null
+package org.argeo.jackrabbit.client;
+
+import java.util.Map;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.spi.RepositoryService;
+import org.apache.jackrabbit.spi.commons.ItemInfoCacheImpl;
+import org.apache.jackrabbit.spi2davex.BatchReadConfig;
+import org.apache.jackrabbit.spi2davex.Spi2davexRepositoryServiceFactory;
+
+/**
+ * Wrapper for {@link Spi2davexRepositoryServiceFactory} in order to create a
+ * {@link ClientDavexRepositoryService}.
+ */
+public class ClientDavexRepositoryServiceFactory extends Spi2davexRepositoryServiceFactory {
+ @Override
+ public RepositoryService createRepositoryService(Map<?, ?> parameters) throws RepositoryException {
+ // retrieve the repository uri
+ String uri;
+ if (parameters == null) {
+ uri = System.getProperty(PARAM_REPOSITORY_URI);
+ } else {
+ Object repoUri = parameters.get(PARAM_REPOSITORY_URI);
+ uri = (repoUri == null) ? null : repoUri.toString();
+ }
+ if (uri == null) {
+ uri = DEFAULT_REPOSITORY_URI;
+ }
+
+ // load other optional configuration parameters
+ BatchReadConfig brc = null;
+ int itemInfoCacheSize = ItemInfoCacheImpl.DEFAULT_CACHE_SIZE;
+ int maximumHttpConnections = 0;
+
+ // since JCR-4120 the default workspace name is no longer set to 'default'
+ // note: if running with JCR Server < 1.5 a default workspace name must
+ // therefore be configured
+ String workspaceNameDefault = null;
+
+ if (parameters != null) {
+ // batchRead config
+ Object param = parameters.get(PARAM_BATCHREAD_CONFIG);
+ if (param != null && param instanceof BatchReadConfig) {
+ brc = (BatchReadConfig) param;
+ }
+
+ // itemCache size config
+ param = parameters.get(PARAM_ITEMINFO_CACHE_SIZE);
+ if (param != null) {
+ try {
+ itemInfoCacheSize = Integer.parseInt(param.toString());
+ } catch (NumberFormatException e) {
+ // ignore, use default
+ }
+ }
+
+ // max connections config
+ param = parameters.get(PARAM_MAX_CONNECTIONS);
+ if (param != null) {
+ try {
+ maximumHttpConnections = Integer.parseInt(param.toString());
+ } catch (NumberFormatException e) {
+ // using default
+ }
+ }
+
+ param = parameters.get(PARAM_WORKSPACE_NAME_DEFAULT);
+ if (param != null) {
+ workspaceNameDefault = param.toString();
+ }
+ }
+
+ if (maximumHttpConnections > 0) {
+ return new ClientDavexRepositoryService(uri, workspaceNameDefault, brc, itemInfoCacheSize,
+ maximumHttpConnections);
+ } else {
+ return new ClientDavexRepositoryService(uri, workspaceNameDefault, brc, itemInfoCacheSize);
+ }
+ }
+
+}
--- /dev/null
+package org.argeo.jackrabbit.client;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.RepositoryFactory;
+import javax.jcr.Session;
+
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.jackrabbit.jcr2dav.Jcr2davRepositoryFactory;
+import org.apache.jackrabbit.jcr2spi.Jcr2spiRepositoryFactory;
+import org.apache.jackrabbit.jcr2spi.RepositoryImpl;
+import org.apache.jackrabbit.spi.RepositoryService;
+import org.apache.jackrabbit.spi.RepositoryServiceFactory;
+import org.apache.jackrabbit.spi.SessionInfo;
+import org.apache.jackrabbit.spi.commons.ItemInfoCacheImpl;
+import org.apache.jackrabbit.spi2davex.BatchReadConfig;
+import org.apache.jackrabbit.spi2davex.RepositoryServiceImpl;
+import org.apache.jackrabbit.spi2davex.Spi2davexRepositoryServiceFactory;
+import org.argeo.jcr.JcrUtils;
+
+/** Minimal client to test JCR DAVEX connectivity. */
+public class JackrabbitClient {
+ final static String JACKRABBIT_REPOSITORY_URI = "org.apache.jackrabbit.repository.uri";
+ final static String JACKRABBIT_DAVEX_URI = "org.apache.jackrabbit.spi2davex.uri";
+ final static String JACKRABBIT_REMOTE_DEFAULT_WORKSPACE = "org.apache.jackrabbit.spi2davex.WorkspaceNameDefault";
+
+ public static void main(String[] args) {
+ String repoUri = args.length == 0 ? "http://root:demo@localhost:7070/jcr/ego" : args[0];
+ String workspace = args.length < 2 ? "home" : args[1];
+
+ Repository repository = null;
+ Session session = null;
+
+ URI uri;
+ try {
+ uri = new URI(repoUri);
+ } catch (URISyntaxException e1) {
+ throw new IllegalArgumentException(e1);
+ }
+
+ if (uri.getScheme().equals("http") || uri.getScheme().equals("https")) {
+
+ RepositoryFactory repositoryFactory = new Jcr2davRepositoryFactory() {
+ @SuppressWarnings("rawtypes")
+ public Repository getRepository(Map parameters) throws RepositoryException {
+ RepositoryServiceFactory repositoryServiceFactory = new Spi2davexRepositoryServiceFactory() {
+
+ @Override
+ public RepositoryService createRepositoryService(Map<?, ?> parameters)
+ throws RepositoryException {
+ Object uri = parameters.get(JACKRABBIT_DAVEX_URI);
+ Object defaultWorkspace = parameters.get(JACKRABBIT_REMOTE_DEFAULT_WORKSPACE);
+ BatchReadConfig brc = null;
+ return new RepositoryServiceImpl(uri.toString(), defaultWorkspace.toString(), brc,
+ ItemInfoCacheImpl.DEFAULT_CACHE_SIZE) {
+
+ @Override
+ protected HttpContext getContext(SessionInfo sessionInfo) throws RepositoryException {
+ HttpClientContext result = HttpClientContext.create();
+ result.setAuthCache(new NonSerialBasicAuthCache());
+ return result;
+ }
+
+ };
+ }
+ };
+ return RepositoryImpl.create(
+ new Jcr2spiRepositoryFactory.RepositoryConfigImpl(repositoryServiceFactory, parameters));
+ }
+ };
+ Map<String, String> params = new HashMap<String, String>();
+ params.put(JACKRABBIT_DAVEX_URI, repoUri.toString());
+ params.put(JACKRABBIT_REMOTE_DEFAULT_WORKSPACE, "main");
+
+ try {
+ repository = repositoryFactory.getRepository(params);
+ if (repository != null)
+ session = repository.login(workspace);
+ else
+ throw new IllegalArgumentException("Repository " + repoUri + " not found");
+ } catch (RepositoryException e) {
+ e.printStackTrace();
+ }
+
+ } else {
+ Path path = Paths.get(uri.getPath());
+ }
+
+ try {
+ Node rootNode = session.getRootNode();
+ NodeIterator nit = rootNode.getNodes();
+ while (nit.hasNext()) {
+ System.out.println(nit.nextNode().getPath());
+ }
+
+ Node newNode = JcrUtils.mkdirs(rootNode, "dir/subdir");
+ System.out.println("Created folder " + newNode.getPath());
+ Node newFile = JcrUtils.copyBytesAsFile(newNode, "test.txt", "TEST".getBytes());
+ System.out.println("Created file " + newFile.getPath());
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(JcrUtils.getFileAsStream(newFile)))) {
+ System.out.println("Read " + reader.readLine());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ newNode.getParent().remove();
+ System.out.println("Removed new nodes");
+ } catch (RepositoryException e) {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package org.argeo.jackrabbit.client;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.http.HttpHost;
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.client.AuthCache;
+
+/**
+ * Implementation of {@link AuthCache} which doesn't use serialization, as it is
+ * not supported by GraalVM at this stage.
+ */
+public class NonSerialBasicAuthCache implements AuthCache {
+ private final Map<HttpHost, AuthScheme> cache;
+
+ public NonSerialBasicAuthCache() {
+ cache = new ConcurrentHashMap<HttpHost, AuthScheme>();
+ }
+
+ @Override
+ public void put(HttpHost host, AuthScheme authScheme) {
+ cache.put(host, authScheme);
+ }
+
+ @Override
+ public AuthScheme get(HttpHost host) {
+ return cache.get(host);
+ }
+
+ @Override
+ public void remove(HttpHost host) {
+ cache.remove(host);
+ }
+
+ @Override
+ public void clear() {
+ cache.clear();
+ }
+
+}
import javax.jcr.RepositoryFactory;
import javax.jcr.Session;
-import org.apache.jackrabbit.jcr2dav.Jcr2davRepositoryFactory;
+import org.apache.jackrabbit.core.security.authentication.LocalAuthContext;
+import org.argeo.jackrabbit.client.ClientDavexRepositoryFactory;
import org.argeo.jcr.ArgeoJcrException;
import org.argeo.jcr.fs.JcrFileSystem;
import org.argeo.jcr.fs.JcrFsException;
+/**
+ * A file system provider based on a JCR repository remotely accessed via the
+ * DAVEX protocol.
+ */
public class DavexFsProvider extends AbstractJackrabbitFsProvider {
- final static String JACKRABBIT_REPOSITORY_URI = "org.apache.jackrabbit.repository.uri";
- final static String JACKRABBIT_REMOTE_DEFAULT_WORKSPACE = "org.apache.jackrabbit.spi2davex.WorkspaceNameDefault";
+// final static String JACKRABBIT_REPOSITORY_URI = "org.apache.jackrabbit.repository.uri";
+// final static String JACKRABBIT_REMOTE_DEFAULT_WORKSPACE = "org.apache.jackrabbit.spi2davex.WorkspaceNameDefault";
private Map<String, JcrFileSystem> fileSystems = new HashMap<>();
String repoKey = repoUri.toString();
if (fileSystems.containsKey(repoKey))
throw new FileSystemAlreadyExistsException("CMS file system already exists for " + repoKey);
- RepositoryFactory repositoryFactory = new Jcr2davRepositoryFactory();
- return tryGetRepo(repositoryFactory, repoUri, "main");
+ RepositoryFactory repositoryFactory = new ClientDavexRepositoryFactory();
+ return tryGetRepo(repositoryFactory, repoUri, "home");
} catch (Exception e) {
throw new ArgeoJcrException("Cannot open file system " + uri, e);
}
private JcrFileSystem tryGetRepo(RepositoryFactory repositoryFactory, URI repoUri, String workspace)
throws IOException {
Map<String, String> params = new HashMap<String, String>();
- params.put(JACKRABBIT_REPOSITORY_URI, repoUri.toString());
- params.put(JACKRABBIT_REMOTE_DEFAULT_WORKSPACE, "main");
+ params.put(ClientDavexRepositoryFactory.JACKRABBIT_DAVEX_URI, repoUri.toString());
+ params.put(ClientDavexRepositoryFactory.JACKRABBIT_REMOTE_DEFAULT_WORKSPACE, "main");
Repository repository = null;
Session session = null;
try {
try {
repoUri = new URI("http", uri.getUserInfo(), uri.getHost(), uri.getPort(), uri.getPath(), null, null);
} catch (URISyntaxException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ throw new IllegalArgumentException(e);
}
String uriStr = repoUri.toString();
String localPath = null;
localPath = uriStr.toString().substring(key.length());
}
}
+ if ("".equals(localPath))
+ localPath = "/";
return fileSystem.getPath(localPath);
}
public static void main(String args[]) {
try {
DavexFsProvider fsProvider = new DavexFsProvider();
- Path path = fsProvider.getPath(new URI("davex://root:demo@localhost:7070/jcr/node/main/home/"));
+ Path path = fsProvider.getPath(new URI("davex://root:demo@localhost:7070/jcr/ego/"));
System.out.println(path);
DirectoryStream<Path> ds = Files.newDirectoryStream(path);
for (Path p : ds) {
import java.util.TreeMap;
import javax.jcr.Binary;
+import javax.jcr.Credentials;
import javax.jcr.NamespaceRegistry;
import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.Node;
*/
public static Session loginOrCreateWorkspace(Repository repository, String workspaceName)
throws RepositoryException {
+ return loginOrCreateWorkspace(repository, workspaceName, null);
+ }
+
+ /**
+ * Login to a workspace with implicit credentials, creates the workspace with
+ * these credentials if it does not already exist.
+ */
+ public static Session loginOrCreateWorkspace(Repository repository, String workspaceName, Credentials credentials)
+ throws RepositoryException {
Session workspaceSession = null;
Session defaultSession = null;
try {
try {
- workspaceSession = repository.login(workspaceName);
+ workspaceSession = repository.login(credentials, workspaceName);
} catch (NoSuchWorkspaceException e) {
// try to create workspace
- defaultSession = repository.login();
+ defaultSession = repository.login(credentials);
defaultSession.getWorkspace().createWorkspace(workspaceName);
- workspaceSession = repository.login(workspaceName);
+ workspaceSession = repository.login(credentials, workspaceName);
}
return workspaceSession;
} finally {