org.apache.jackrabbit.vault.fs.api.RepositoryAddress Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
/*
* 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.
*/
package org.apache.jackrabbit.vault.fs.api;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.BitSet;
import javax.jcr.Credentials;
import javax.jcr.SimpleCredentials;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* The repository address locates a jcr repository in with a URI representation.
* It is composed out of a uri and accepts the following formats:
*
*
* - scheme://host:port/
*
- scheme://host:port/prefix
*
- scheme://host:port/prefix/workspace
*
- scheme://host:port/prefix/workspace/jcr_root/path
*
*/
public class RepositoryAddress {
/**
* the (virtual) jcr root.
*/
public final static String JCR_ROOT = "/jcr:root";
/**
* the final uri
*/
private final URI uri;
/**
* the specific part (uri up to excluding the workspace segment)
*/
private final URI specific;
/**
* the workspace or null
*/
private final String workspace;
/**
* the path
*/
private final String path;
/**
* Creates a new default repository address.
* @param uri the uri
* @throws URISyntaxException if the uri is not valid
*/
public RepositoryAddress(@NotNull String uri) throws URISyntaxException {
this(new URI(uri));
}
/**
* Creates a new default repository address.
* @param uri the uri
* @throws URISyntaxException if the uri is not valid
*/
public RepositoryAddress(@NotNull URI uri) throws URISyntaxException {
// decode uri
String path = uri.getPath();
String workspace;
String prefix = "/";
String localPath = "/";
if (path.length() == 0 || "/".equals(path)) {
workspace = "-";
localPath = "/";
} else if (!uri.isAbsolute()) {
// fix format: /wsp/path
int idx1 = path.indexOf('/', 1);
if (idx1 < 0) {
workspace = path.substring(1);
} else {
workspace = path.substring(1, idx1);
localPath = path.substring(idx1);
}
} else {
if (path.charAt(path.length() -1) != '/') {
path = path + "/";
}
int idx1 = -1;
int idx2 = 0;
int idx3 = path.indexOf('/', 1);
while (idx3 > 0) {
String segment = path.substring(idx2, idx3);
if (segment.equals(JCR_ROOT)) {
break;
}
idx1 = idx2;
idx2 = idx3;
idx3 = path.indexOf('/', idx3 + 1);
}
if (idx3 < 0) {
// no jcr_root found
// special case for rmi backward compatibility
if (uri.getScheme() != null && "rmi".equals(uri.getScheme())) {
idx1 = path.indexOf('/', 1);
idx2 = path.indexOf('/', idx1 + 1);
if (idx2 < 0) {
workspace = "-";
prefix = path.substring(0, idx1);
localPath = "/";
} else {
workspace = path.substring(idx1 + 1, idx2);
prefix = path.substring(0, idx1);
int end = path.length();
if (end != idx2 + 1) {
end--;
}
localPath = path.substring(idx2, end);
}
} else {
workspace = idx1 < 0 ? "-" : path.substring(idx1+1,idx2);
prefix = idx1 <= 0 ? "/" : path.substring(0, idx1);
localPath = "/";
}
} else {
workspace = path.substring(idx1 + 1, idx2);
prefix = path.substring(0, idx1);
int end = path.length();
if (end - idx3 > 1) {
end--;
}
localPath = path.substring(idx3, end);
}
}
// sanitize HTTP address (probably wrong place)
if (uri.getScheme() != null && uri.getScheme().startsWith("http")) {
if ("/".equals(prefix) || "/crx".equals(prefix)) {
prefix = "/crx/server";
workspace = "-";
}
}
if (prefix.length() == 0) {
prefix = "/";
}
this.path = localPath;
this.workspace = workspace;
this.specific = uri.resolve(prefix);
StringBuilder buf = new StringBuilder(specific.toString());
if (buf.charAt(buf.length() - 1) != '/') {
buf.append('/');
}
buf.append(workspace);
buf.append(JCR_ROOT);
if (!"/".equals(localPath)) {
buf.append(escapePath(localPath));
}
this.uri = new URI(buf.toString());
}
/**
* Private constructor that sets all fields.
* @param uri the address uri
* @param specific the specific uri
* @param workspace the workspace
* @param path the path
*/
private RepositoryAddress(@NotNull URI uri, @NotNull URI specific, @Nullable String workspace, @NotNull String path) {
this.uri = uri;
this.specific = specific;
this.workspace = workspace;
this.path = path;
}
/**
* Returns the uri of this address
* @return the uri of this address
*/
@NotNull
public URI getURI() {
return uri;
}
/**
* Returns a new repository address with the given path.
* @param path the path to include in the new address
* @return a new repository address
*/
@NotNull
public RepositoryAddress resolve(@Nullable String path) {
if (path == null || path.length() == 0 || ".".equals(path) || "./".equals(path)) {
return this;
}
StringBuilder newPath = new StringBuilder(specific.getPath());
newPath.append("/");
newPath.append(workspace);
newPath.append(JCR_ROOT);
if (path.charAt(0) != '/') {
if (this.path.endsWith("/")) {
path = this.path + path;
} else {
path = this.path + "/" + path;
}
}
newPath.append(escapePath(path));
URI uri = specific.resolve(newPath.toString());
return new RepositoryAddress(uri, specific, workspace, path);
}
/**
* Returns the name of the workspace or {@code null} if the default
* workspace is used.
* @return the name of the workspace or {@code null}
*/
@Nullable
public String getWorkspace() {
return "-".equals(workspace) ? null : workspace;
}
/**
* Returns the specific part of the uri, i.e. the part that is used to
* actually connect to the repository
* @return the specific part
*/
@NotNull
public URI getSpecificURI() {
return specific;
}
/**
* Returns the path to a repository item. If not explicit path is specified
* by this address the root path '/' is returned.
* @return the path to a repository item.
*/
@NotNull
public String getPath() {
return path;
}
/**
* Returns JCR credentials from the URI or {@code null} if no user info
* is specified.
* @return the creds
*/
@Nullable
public Credentials getCredentials() {
String userinfo = uri.getUserInfo();
if (userinfo == null) {
return null;
} else {
int idx = userinfo.indexOf(':');
if (idx < 0) {
return new SimpleCredentials(userinfo, new char[0]);
} else {
return new SimpleCredentials(
userinfo.substring(0, idx),
userinfo.substring(idx+1).toCharArray());
}
}
}
/**
* {@inheritDoc}
*
* @return same as {@link #getURI() getURI().toString()} with obfuscated user info
*/
@Override
@NotNull
public String toString() {
final URI uri = getURI();
final String userInfo = uri.getRawUserInfo();
if (userInfo != null) {
return uri.toString().replace(userInfo, "******:******");
} else {
return uri.toString();
}
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return getURI().hashCode();
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof RepositoryAddress) {
return getURI().equals(((RepositoryAddress) obj).getURI());
}
return false;
}
private static BitSet URISaveEx;
static {
URISaveEx = new BitSet(256);
int i;
for (i = 'a'; i <= 'z'; i++) {
URISaveEx.set(i);
}
for (i = 'A'; i <= 'Z'; i++) {
URISaveEx.set(i);
}
for (i = '0'; i <= '9'; i++) {
URISaveEx.set(i);
}
URISaveEx.set('-');
URISaveEx.set('_');
URISaveEx.set('.');
URISaveEx.set('!');
URISaveEx.set('~');
URISaveEx.set('*');
URISaveEx.set('\'');
URISaveEx.set('(');
URISaveEx.set(')');
URISaveEx.set('/');
}
private static final char[] hexTable = "0123456789abcdef".toCharArray();
/**
* Does an URL encoding of the {@code string} using the
* {@code escape} character. The characters that don't need encoding
* are those defined 'unreserved' in section 2.3 of the 'URI generic syntax'
* RFC 2396, but without the escape character. If {@code isPath} is
* {@code true}, additionally the slash '/' is ignored, too.
*
* @param string the string to encode.
* @return the escaped string
* @throws NullPointerException if {@code string} is @{code null}.
*/
@NotNull
private static String escapePath(@NotNull String string) {
try {
byte[] bytes = string.getBytes("utf-8");
StringBuilder out = new StringBuilder(bytes.length);
for (byte aByte : bytes) {
int c = aByte & 0xff;
if (URISaveEx.get(c) && c != '%') {
out.append((char) c);
} else {
out.append('%');
out.append(hexTable[(c >> 4) & 0x0f]);
out.append(hexTable[(c) & 0x0f]);
}
}
return out.toString();
} catch (UnsupportedEncodingException e) {
throw new InternalError(e.toString());
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy