298 lines
12 KiB
C#
298 lines
12 KiB
C#
|
/*
|
|||
|
* java.cs
|
|||
|
*
|
|||
|
* This source file is part of the FoundationDB open source project
|
|||
|
*
|
|||
|
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
|
|||
|
*
|
|||
|
* 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.
|
|||
|
*/
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.IO;
|
|||
|
using System.Linq;
|
|||
|
using System.Text;
|
|||
|
|
|||
|
namespace vexillographer
|
|||
|
{
|
|||
|
class java : BindingWriter
|
|||
|
{
|
|||
|
private static string formatComment(int indentTabs, string commentText)
|
|||
|
{
|
|||
|
string tabs = "";
|
|||
|
for(int i=0; i<indentTabs; i++) tabs += "\t";
|
|||
|
return tabs + "/**" +
|
|||
|
string.Join( "",
|
|||
|
commentText.Split('\n')
|
|||
|
.Select( line=> "\n" + tabs + " * " + line.Trim() ) )
|
|||
|
+ "\n" + tabs + " *" + "/";
|
|||
|
}
|
|||
|
|
|||
|
private static string replaceTicks(string input)
|
|||
|
{
|
|||
|
int startIdx = input.IndexOf("``");
|
|||
|
int lastReplaceEnd = 0;
|
|||
|
string output = "";
|
|||
|
while (startIdx >= 0)
|
|||
|
{
|
|||
|
output += input.Substring(lastReplaceEnd, startIdx - lastReplaceEnd);
|
|||
|
int closingIdx = input.IndexOf("``", startIdx + 2);
|
|||
|
if (closingIdx < 0)
|
|||
|
throw new InvalidDataException("No closing double tick");
|
|||
|
output += "{@code " + input.Substring(startIdx + 2, closingIdx - startIdx - 2) + "}";
|
|||
|
lastReplaceEnd = closingIdx + 2;
|
|||
|
startIdx = input.IndexOf("``", lastReplaceEnd);
|
|||
|
}
|
|||
|
output += input.Substring(lastReplaceEnd);
|
|||
|
return output;
|
|||
|
}
|
|||
|
|
|||
|
private static string getEnum(Option o)
|
|||
|
{
|
|||
|
string mainComment = o.comment == "" ? "Currently undocumented." : o.comment;
|
|||
|
if (!mainComment.EndsWith("."))
|
|||
|
mainComment += ".";
|
|||
|
mainComment = replaceTicks(mainComment);
|
|||
|
return formatComment(1, mainComment) +
|
|||
|
String.Format("\n{2}\t{0}({1})", o.name.ToUpper(), o.code, o.isDeprecated() ? "\t@Deprecated\n" : "");
|
|||
|
}
|
|||
|
|
|||
|
class ScopeOptions
|
|||
|
{
|
|||
|
public bool isPublic;
|
|||
|
public bool isSettableOption;
|
|||
|
public String comment;
|
|||
|
|
|||
|
public ScopeOptions(bool isSettable, String comment, bool isPublic = true) {
|
|||
|
this.isPublic = isPublic;
|
|||
|
this.isSettableOption = isSettable;
|
|||
|
this.comment = comment;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private static Dictionary<Scope, ScopeOptions> scopeDocOptions = new Dictionary<Scope, ScopeOptions>()
|
|||
|
{
|
|||
|
{ Scope.NetworkOption, new ScopeOptions(true,
|
|||
|
"A set of options that can be set globally for the {@link FDB FoundationDB API}.") },
|
|||
|
{ Scope.ClusterOption, new ScopeOptions(true,
|
|||
|
"A set of options that can be set on a {@link Cluster}.") },
|
|||
|
{ Scope.DatabaseOption, new ScopeOptions(true,
|
|||
|
"A set of options that can be set on a {@link Database}.") },
|
|||
|
{ Scope.TransactionOption, new ScopeOptions(true,
|
|||
|
"A set of options that can be set on a {@link Transaction}.") },
|
|||
|
{ Scope.StreamingMode, new ScopeOptions(false,
|
|||
|
"Options that control the way the Java binding performs range reads. These options can be passed to {@link Transaction#getRange(byte[], byte[], int, boolean, StreamingMode) Transaction.getRange(...)}.") },
|
|||
|
{ Scope.MutationType, new ScopeOptions(false,
|
|||
|
"A set of operations that can be performed atomically on a database. These are used as parameters to {@link Transaction#mutate(MutationType, byte[], byte[])}.") },
|
|||
|
{ Scope.ConflictRangeType, new ScopeOptions(false,
|
|||
|
"Conflict range types used internally by the C API.", false) },
|
|||
|
{ Scope.ErrorPredicate, new ScopeOptions(true,
|
|||
|
"Error code predicates for binding writers and non-standard layer implementers.") },
|
|||
|
};
|
|||
|
|
|||
|
private static bool scopeIsSettableOption(Scope s) {
|
|||
|
return s != Scope.StreamingMode && s != Scope.MutationType && s != Scope.ConflictRangeType;
|
|||
|
}
|
|||
|
|
|||
|
private static string toCamelCase(string optionName) {
|
|||
|
return string.Join("",
|
|||
|
optionName
|
|||
|
.Split('_')
|
|||
|
.Select( s=>s.Substring(0,1).ToUpper() + s.Substring(1) )
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
private static string toSetFuncName(string optionName) {
|
|||
|
return "set" + toCamelCase(optionName);
|
|||
|
}
|
|||
|
|
|||
|
private static string toPredicateFuncName(string optionName) {
|
|||
|
return "is" + toCamelCase(optionName);
|
|||
|
}
|
|||
|
|
|||
|
private static string getJavaTypeName(ParamType t)
|
|||
|
{
|
|||
|
switch (t)
|
|||
|
{
|
|||
|
case ParamType.Int: return "long";
|
|||
|
case ParamType.Bytes: return "byte[]";
|
|||
|
case ParamType.String: return "String";
|
|||
|
default: throw new InvalidDataException("Unsupported operation type");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private static void writeOptionsClass(TextWriter outFile, Scope scope, IEnumerable<Option> options)
|
|||
|
{
|
|||
|
string className = scope.ToString() + "s";
|
|||
|
outFile.WriteLine( "package com.apple.cie.foundationdb;" );
|
|||
|
outFile.WriteLine();
|
|||
|
|
|||
|
outFile.WriteLine(formatComment(0, scopeDocOptions[scope].comment +
|
|||
|
(options.Count() == 0 ? "\n\nThere are currently no options available." : "")
|
|||
|
));
|
|||
|
outFile.WriteLine("public class {0} extends OptionsSet {{", className);
|
|||
|
outFile.WriteLine("\tpublic {0}( OptionConsumer consumer ) {{ super(consumer); }}", className);
|
|||
|
foreach(var option in options) {
|
|||
|
if (!option.hidden) {
|
|||
|
outFile.WriteLine();
|
|||
|
if (option.comment != "")
|
|||
|
{
|
|||
|
string comment = option.comment;
|
|||
|
if (!comment.EndsWith("."))
|
|||
|
comment += ".";
|
|||
|
if (option.paramDesc != null)
|
|||
|
comment += "\n\n@param value " + option.paramDesc;
|
|||
|
outFile.WriteLine(formatComment(1, replaceTicks(comment)));
|
|||
|
}
|
|||
|
if (option.isDeprecated())
|
|||
|
outFile.WriteLine("\t@Deprecated");
|
|||
|
if (option.paramType == ParamType.None)
|
|||
|
outFile.WriteLine("\tpublic void {0}() {{ setOption({1}); }}", toSetFuncName(option.name), option.code);
|
|||
|
else
|
|||
|
outFile.WriteLine("\tpublic void {0}({2} value) {{ setOption({1}, value); }}", toSetFuncName(option.name), option.code, getJavaTypeName(option.paramType));
|
|||
|
}
|
|||
|
}
|
|||
|
outFile.WriteLine("}");
|
|||
|
}
|
|||
|
|
|||
|
private static void writePredicateClass(TextWriter outFile, Scope scope, IEnumerable<Option> options)
|
|||
|
{
|
|||
|
string className = scope.ToString() + "s";
|
|||
|
outFile.WriteLine(
|
|||
|
@"package com.apple.cie.foundationdb;
|
|||
|
|
|||
|
import com.apple.cie.foundationdb.async.CloneableException;
|
|||
|
|
|||
|
/**
|
|||
|
* An Error from the native layers of FoundationDB. Each {@code FDBException} sets
|
|||
|
* the {@code message} of the Exception.
|
|||
|
*
|
|||
|
*/
|
|||
|
public class FDBException extends RuntimeException implements CloneableException {
|
|||
|
private static final long serialVersionUID = 1L;
|
|||
|
private final int code;
|
|||
|
|
|||
|
/**
|
|||
|
* A general constructor. Not for use by client code.
|
|||
|
*/
|
|||
|
public FDBException(String message, int code) {
|
|||
|
super(message);
|
|||
|
this.code = code;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Gets the code for this error. For internal use.
|
|||
|
* @return the internal FDB error code.
|
|||
|
*/
|
|||
|
public int getCode() {
|
|||
|
return code;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if this {@code FDBException} represents a success code from the native layer.
|
|||
|
*
|
|||
|
* @return {@code true} if this error represents success, {@code false} otherwise
|
|||
|
*/
|
|||
|
public boolean isSuccess() {
|
|||
|
return getCode() == 0;
|
|||
|
}
|
|||
|
|
|||
|
@Override
|
|||
|
public Exception retargetClone() {
|
|||
|
FDBException exception = new FDBException(getMessage(), code);
|
|||
|
exception.initCause(this);
|
|||
|
return exception;
|
|||
|
}
|
|||
|
");
|
|||
|
|
|||
|
foreach(var option in options) {
|
|||
|
if (!option.hidden) {
|
|||
|
outFile.WriteLine();
|
|||
|
if (option.comment != "")
|
|||
|
{
|
|||
|
string comment = option.comment;
|
|||
|
if (!comment.EndsWith("."))
|
|||
|
comment += ".";
|
|||
|
if (option.paramDesc != null)
|
|||
|
comment += "\n\n@param value " + option.paramDesc;
|
|||
|
outFile.WriteLine(formatComment(1, replaceTicks(comment)));
|
|||
|
}
|
|||
|
if (option.isDeprecated())
|
|||
|
outFile.WriteLine("\t@Deprecated");
|
|||
|
outFile.WriteLine("\tpublic boolean {0}() {{ return FDB.evalErrorPredicate({1}, this.code); }}", toPredicateFuncName(option.name), option.code);
|
|||
|
}
|
|||
|
}
|
|||
|
outFile.WriteLine("}");
|
|||
|
}
|
|||
|
|
|||
|
private static void writeEnumClass(TextWriter outFile, Scope scope, IEnumerable<Option> options)
|
|||
|
{
|
|||
|
string scopeName = scope.ToString();
|
|||
|
|
|||
|
outFile.WriteLine( "package com.apple.cie.foundationdb;" );
|
|||
|
outFile.WriteLine();
|
|||
|
outFile.WriteLine(formatComment(0, scopeDocOptions[scope].comment +
|
|||
|
(options.Count() == 0 ? "\n\nThere are currently no options available." : "")));
|
|||
|
|
|||
|
outFile.WriteLine("{0}enum {1} {{", scopeDocOptions[scope].isPublic ? "public " : "", scopeName);
|
|||
|
outFile.WriteLine(string.Join(",\n\n", options.Where(f => !f.hidden).Select(f => getEnum(f)).ToArray()) + ";");
|
|||
|
outFile.WriteLine(
|
|||
|
@"
|
|||
|
private final int code;
|
|||
|
|
|||
|
{0}(int code) {{
|
|||
|
this.code = code;
|
|||
|
}}
|
|||
|
|
|||
|
/**
|
|||
|
* Gets the FoundationDB native-level constant code for a {{@code {0}}}.
|
|||
|
*
|
|||
|
* @return the native code for a FoundationDB {{@code {0}}} constant.
|
|||
|
*/
|
|||
|
public int code() {{
|
|||
|
return this.code;
|
|||
|
}}
|
|||
|
}}", scopeName);
|
|||
|
}
|
|||
|
|
|||
|
public void writeFiles(string outputDirectory, IEnumerable<Option> options)
|
|||
|
{
|
|||
|
foreach (Scope s in Enum.GetValues(typeof(Scope)))
|
|||
|
{
|
|||
|
if (!Directory.Exists(outputDirectory))
|
|||
|
throw new Exception(string.Format("Directory {0} does not exist", outputDirectory));
|
|||
|
|
|||
|
string className = s.ToString();
|
|||
|
if (scopeDocOptions[s].isSettableOption) className += "s";
|
|||
|
string filePath = Path.Combine(outputDirectory, (s == Scope.ErrorPredicate ? "FDBException" : className) + ".java");
|
|||
|
using (var javaFile = System.IO.File.Open(filePath,
|
|||
|
System.IO.FileMode.Create, System.IO.FileAccess.Write))
|
|||
|
{
|
|||
|
TextWriter outFile = new StreamWriter(javaFile);
|
|||
|
outFile.NewLine = "\r";
|
|||
|
if (scopeDocOptions[s].isSettableOption) {
|
|||
|
if(s == Scope.ErrorPredicate)
|
|||
|
writePredicateClass(outFile, s, options.Where(o => o.scope == s).OrderBy(o=>o.comment==""));
|
|||
|
else
|
|||
|
writeOptionsClass(outFile, s, options.Where(o => o.scope == s).OrderBy(o=>o.comment==""));
|
|||
|
}
|
|||
|
else
|
|||
|
writeEnumClass(outFile, s, options.Where(o => o.scope == s));
|
|||
|
outFile.Flush();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|