blob: ed4d9880d6c7f8a6715a91ca3570709172b28972 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package io.v.syncbase.v23.services.syncbase.util;
import com.google.common.base.Charsets;
import java.io.UnsupportedEncodingException;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import io.v.impl.google.naming.NamingUtil;
import io.v.v23.V;
import io.v.v23.context.VContext;
import io.v.v23.namespace.Namespace;
import io.v.v23.naming.GlobReply;
import io.v.v23.verror.VException;
/**
* Various NoSQL utility methods.
*/
public class Util {
/**
* Returns the start of the row range for the given prefix.
*/
public static String prefixRangeStart(String prefix) {
return prefix;
}
/**
* Returns the limit of the row range for the given prefix.
*/
public static String prefixRangeLimit(String prefix) {
// We convert a string to a byte[] array, which can be thought of as a base-256
// number. The code below effectively adds 1 to this number, then chops off any
// trailing 0x00 bytes. If the input string consists entirely of 0xFF, an empty string
// will be returned.
try {
byte[] bytes = prefix.getBytes("ISO8859-1");
int last = bytes.length - 1;
for (; last >= 0 && bytes[last] == (byte) 0xFF; --last);
if (last < 0) {
return "";
}
bytes[last] += 1;
return new String(bytes, 0, last + 1, "ISO8859-1");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("JVM must support ISO8859-1 char encoding", e);
}
}
/**
* Performs {@link Namespace#glob Namespace.glob("name/*")} and returns a
* sorted list of results.
*
* @param ctx Vanadium context
* @param globName name used for globbing
* @return a sorted list of results of
* {@link Namespace#glob Namespace.glob("name/*")}
* @throws VException if a glob error occurred
*/
public static String[] list(VContext ctx, String globName) throws VException {
Namespace n = V.getNamespace(ctx);
ArrayList<String> names = new ArrayList<String>();
try {
for (GlobReply reply : n.glob(ctx, NamingUtil.join(globName, "*"))) {
if (reply instanceof GlobReply.Entry) {
String fullName = ((GlobReply.Entry) reply).getElem().getName();
// NOTE(nlacasse): The names that come back from Glob are all
// rooted. We only want the last part of the name, so we must chop
// off everything before the final '/'. Since endpoints can
// themselves contain slashes, we have to remove the endpoint from
// the name first.
String name = NamingUtil.splitAddressName(fullName).get(1);
int idx = name.lastIndexOf('/');
if (idx != -1) {
name = name.substring(idx + 1, name.length());
}
names.add(name);
} else if (reply instanceof GlobReply.Error) {
throw ((GlobReply.Error) reply).getElem().getError();
} else if (reply == null) {
throw new VException("null glob() reply");
} else {
throw new VException("Unrecognized glob() reply type: " + reply.getClass());
}
}
} catch (RuntimeException e) { // error during iteration
throw (VException) e.getCause();
}
Collections.sort(names, Collator.getInstance());
return names.toArray(new String[names.size()]);
}
/**
* Returns the UTF-8 encoding of the provided string.
*/
public static byte[] getBytes(String s) {
if (s == null) {
s = "";
}
return s.getBytes(Charsets.UTF_8);
}
/**
* Returns the UTF-8 decoded string.
*/
public static String getString(byte[] bytes) {
return new String(bytes, Charsets.UTF_8);
}
private Util() {}
}