| // 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() {} |
| } |