![JAR search and dependency download from the Maven repository](/logo.png)
com.incapture.rapgen.AbstractTTreeDotNet Maven / Gradle / Ivy
/**
* The MIT License (MIT)
*
* Copyright (c) 2011-2016 Incapture Technologies LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.incapture.rapgen;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.RecognizerSharedState;
import org.antlr.runtime.tree.TreeNodeStream;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import com.incapture.rapgen.annotations.AddressableAnnotation;
import com.incapture.rapgen.annotations.BeanAnnotation;
import com.incapture.rapgen.annotations.CacheableAnnotation;
import com.incapture.rapgen.annotations.DeprecatedAnnotation;
import com.incapture.rapgen.annotations.ExtendsAnnotation;
import com.incapture.rapgen.annotations.IndexedAnnotation;
import com.incapture.rapgen.annotations.StorableAnnotation;
import com.incapture.rapgen.annotations.storable.StorableField;
import com.incapture.rapgen.annotations.storable.StorableFieldType;
/**
* This class is used as the base for the parser - we call methods in this class from the Tree walker code.
*
* @author amkimian
*
*/
public abstract class AbstractTTreeDotNet extends AbstractTTree {
private static final String COMMONTEST_LOC = "Test/";
private static final String COMMONSHARED_LOC = "Generated/";
private static final String DEFAULT_PACKAGE = "rapture.common";
/**
* So this abstract tree will be used to host a number of generated files with a generated file simply being a list of templates ordered by some means
*
* We can add a template to a file + section
*/
private Map> kernelTemplates = new HashMap>();
private Map> apiTemplates = new HashMap>();
/**
* Here we store type information (name and package really)
*
*/
private Map typeToPackage = new HashMap();
private Map schemesMap = new HashMap();
/**
* Return the type imports for a given api.
*
* @param api
* @return
*/
protected String getTypeImports(String api) {
Set types = importsForApiType.get(api);
// TODO: We should surely be using a string template for this.
StringBuffer ret = new StringBuffer();
if (types != null) {
for (String type : types) {
ret.append("using ");
ret.append(getPackage(type));
ret.append(".");
ret.append(type);
ret.append(";\n");
}
}
return ret.toString();
}
/**
* Add a package to the type -%gt; package map for imports into the API file
*
* @param type
* - the type of object
* @param pkg
* - the package where the type belongs
*/
protected void addTypeImport(String type, String pkg) {
typeToPackage.put(type, pkg);
}
private Map> importsForApiType = new HashMap>();
protected void addImportForApi(String api, String typeName) {
if (!typeName.isEmpty()) {
if (!importsForApiType.containsKey(api)) {
Set types = new HashSet();
importsForApiType.put(api, types);
}
importsForApiType.get(api).add(typeName);
}
}
/**
* We need to break up the entitlement to parse out the dynamic entitlements and their associated arguments. So now we need a way to re-assemble for
* documentation etc. Example string: /user/read/$d(docURI)
*
* @param regularEntitlements
* - list of regular entitlement paths e.g. /user /read
* @param dynamicEntitlements
* - map of Strings where key is the wildcard and value is the URI arg
* @return - full entitlement string
*/
protected String reassembleFullEntitlmentPath(List regularEntitlements, Map dynamicEntitlements) {
StringBuilder fullEntBuilder = new StringBuilder();
for (String s : regularEntitlements) {
fullEntBuilder.append(s);
}
for (Map.Entry entry : dynamicEntitlements.entrySet()) {
fullEntBuilder.append("/$").append(entry.getKey()).append("(").append(entry.getValue()).append(")");
}
return fullEntBuilder.toString();
}
private Map entPaths = new HashMap();
/**
* This generates the entitlement name for a given api and a path.
*
* @param apiName
* @param path
* @return
*/
protected String generateEntName(String apiName, String path) {
String upName = apiName.toUpperCase() + "_" + path.toUpperCase();
String normName = upName.replaceAll("[/()]", "");
entPaths.put(normName, path);
return normName;
}
protected Map getEntPaths() {
return entPaths;
}
protected void addImportForApi(String api, Set params) {
for (String t : params) {
addImportForApi(api, t);
}
}
public void dumpFiles(String outputKernelFolder, String outputApiFolder) {
dumpFor(outputKernelFolder, kernelTemplates);
dumpFor(outputApiFolder, apiTemplates);
}
public void dumpFor(String outputFolder, Map> templates) {
// For each file, dump the templates
for (Map.Entry> file : templates.entrySet()) {
String outputFile = outputFolder + "/" + file.getKey();
File f = new File(outputFile);
f.getParentFile().mkdirs();
BufferedWriter bow = null;
try {
bow = new BufferedWriter(new FileWriter(f));
Set sections = file.getValue().keySet();
SortedSet sorted = new TreeSet();
sorted.addAll(sections);
for (String sec : sorted) {
bow.write(file.getValue().get(sec).toString());
bow.newLine();
}
bow.close();
} catch (IOException e) {
System.err.println(e.getMessage());
} finally {
if (bow != null) {
try {
bow.close();
} catch (IOException e) {
}
}
}
}
}
protected String prefixCase(String part) {
StringBuffer ret = new StringBuffer();
ret.append(part.substring(0, 1).toUpperCase());
ret.append(part.substring(1));
return ret.toString();
}
/**
* Return the full filename for a java file given an api type and its name
*
* @param api
* @param name
* @param suffix
* @return
*/
protected String getFileNameForType(String sdkName, String api, String name, String suffix) {
if (sdkName == null) {
return String.format(COMMONSHARED_LOC, "/") + api.toLowerCase() + "/" + prefixCase(name) + suffix + ".cs";
} else {
return String.format(COMMONSHARED_LOC, sdkName + "/") + api.toLowerCase() + "/" + prefixCase(name) + suffix + ".cs";
}
}
protected String getFileNameForType(String api, String name, String suffix) {
return getFileNameForType(null, api, name, suffix);
}
protected String getTestFileNameForType(String sdkName, String api, String name, String suffix) {
if (sdkName == null) {
return String.format(COMMONTEST_LOC, "/") + api.toLowerCase() + "/" + prefixCase(name) + suffix + "Test.cs";
} else {
return String.format(COMMONTEST_LOC, sdkName + "/") + api.toLowerCase() + "/" + prefixCase(name) + suffix + "Test.cs";
}
}
protected String getTestFileNameForType(String api, String name, String suffix) {
return getTestFileNameForType(null, api, name, suffix);
}
protected void addApiTemplate(String fileName, String section, StringTemplate template) {
if (!apiTemplates.containsKey(fileName)) {
Map t = new HashMap();
apiTemplates.put(fileName, t);
}
apiTemplates.get(fileName).put(section, template);
}
protected void addKernelTemplate(String fileName, String section, StringTemplate template) {
System.out.println("Adding kernel template " + fileName);
if (!kernelTemplates.containsKey(fileName)) {
Map t = new HashMap();
kernelTemplates.put(fileName, t);
}
kernelTemplates.get(fileName).put(section, template);
}
protected void addType(String typeName, String packageName, BeanAnnotation bean, CacheableAnnotation cacheable, AddressableAnnotation addressable,
StorableAnnotation storable, ExtendsAnnotation extend, DeprecatedAnnotation deprecated, IndexedAnnotation indexed, String sdkName,
Map fieldNameToType, List beanFields, List constructors) {
boolean isBean = bean != null || storable != null;
typeToPackage.put(typeName, packageName);
if (fieldNameToType != null) {
FieldTypesRepo.INSTANCE.setClassFields(typeName, fieldNameToType);
}
if (addressable != null) {
schemesMap.put(addressable.getScheme(), addressable.isSchemePrimitive());
}
STAttrMap beanClassAttributes = new STAttrMap().put("name", typeName).put("fields", beanFields).put("package", packageName);
STAttrMap storageMethodAttributes = new STAttrMap().put("name", typeName).put("package", packageName);
if (isBean) {
if (storable == null && extend != null) {
// Okay, this is a special case. I want to extend something
// that
// may be a Storable.
// I don't want to ag the subclass as Storable too because
// that's silly.
// So there's going to be some duplication here.
if (deprecated != null) {
beanClassAttributes.put("deprecated", deprecated.getReason());
}
if (indexed != null) {
beanClassAttributes.put("indexed", indexed.getFields());
storageMethodAttributes.put("indexed", indexed.getFields());
}
beanClassAttributes.put("extend", extend.getMainClass());
StringTemplate beanClass = getTemplateLib().getInstanceOf("beanClass", beanClassAttributes);
String apiFullPath = "Generated/Types/" + typeName + ".cs";
// TODO HACK ALERT
if (typeName.indexOf("Storage") > 0) addKernelTemplate(apiFullPath, "1", beanClass);
else addApiTemplate(apiFullPath, "1", beanClass);
} else {
List beanAdders = new LinkedList();
List storageAdders = new LinkedList();
List builderAdders = new LinkedList();
List builderFields = new LinkedList();
List storageFields = new LinkedList();
if (storable != null) {
beanClassAttributes.put("storable", Boolean.TRUE);
List pathFields = storable.getFields();
for (StorableField field : pathFields) {
STAttrMap builderAdderMap = new STAttrMap().put("name", field.getName()).put("separator", storable.getSeparator());
if (storable.getEncodingType().length() > 0) {
builderAdderMap.put("encoding", storable.getEncodingType());
}
StringTemplate builderAdder = getTemplateLib().getInstanceOf("builderAdder", builderAdderMap);
builderAdders.add(builderAdder);
if (StorableFieldType.ID.equals(field.getType())) {
StringTemplate beanAdder = getTemplateLib().getInstanceOf("beanAdder", new STAttrMap().put("name", field.getName()));
beanAdders.add(beanAdder);
StringTemplate storageAdder = getTemplateLib().getInstanceOf("storageAdder", new STAttrMap().put("name", field.getName()));
storageAdders.add(storageAdder);
String fieldType = fieldNameToType.get(field.getName());
if (fieldType == null || fieldType.length() == 0) {
if (extend != null && extend.getSuperclass() != null) {
Map superClassTypes = FieldTypesRepo.INSTANCE.getFieldToType(extend.getSuperclass());
if (superClassTypes != null) {
fieldType = superClassTypes.get(field.getName());
} else {
System.out.println(String.format("Tried %s from superclass %s... got null superclass", field.getName(),
extend.getSuperclass()));
}
}
}
StringTemplate builderField = getTemplateLib().getInstanceOf("builderEntry",
new STAttrMap().put("fieldName", field.getName()).put("name", typeName).put("fieldType", fieldType));
builderFields.add(builderField);
storageFields.add(getTemplateLib().getInstanceOf("storageField",
new STAttrMap().put("fieldName", field.getName()).put("fieldType", fieldType)));
}
beanClassAttributes.put("adders", beanAdders);
storageMethodAttributes.put("adders", storageAdders).put("fields", storageFields);
}
storageMethodAttributes.put("cacheable", cacheable == null ? false : true);
if (sdkName != null) {
beanClassAttributes.put("sdkName", sdkName);
storageMethodAttributes.put("sdkName", sdkName);
}
}
Collection importList = ImporterRegistry.getImportList(fieldNameToType.values());
if (deprecated != null) {
beanClassAttributes.put("deprecated", deprecated.getReason());
}
if (indexed != null) {
beanClassAttributes.put("indexed", indexed.getFields());
}
if (extend != null) {
beanClassAttributes.put("extend", extend.getSuperclass());
}
if (constructors != null) {
importList.addAll(ImporterRegistry.getImportList(constructors));
}
beanClassAttributes.put("importList", importList);
StringTemplate beanClass = getTemplateLib().getInstanceOf("beanClass", beanClassAttributes);
String apiFullPath = "Generated/Types/" + typeName + ".cs";
addApiTemplate(apiFullPath, "1", beanClass);
}
}
}
@SuppressWarnings("unused")
private StringTemplate getAddressMethod(String scheme) {
return getTemplateLib().getInstanceOf("beanAddressMethod", new STAttrMap().put("scheme", scheme));
}
protected StringTemplate getDebugMethod(Set fieldNames) {
List equalsEntries = new LinkedList();
for (String fieldName : fieldNames) {
StringTemplate currentEntry = getTemplateLib().getInstanceOf("beanDebugEntry", new STAttrMap().put("fieldName", fieldName));
equalsEntries.add(currentEntry);
}
return getTemplateLib().getInstanceOf("beanDebug", new STAttrMap().put("entries", equalsEntries));
}
@SuppressWarnings("unused")
private StringTemplate getEqualsMethod(Set fieldNames) {
List equalsEntries = new LinkedList();
for (String fieldName : fieldNames) {
StringTemplate currentEntry = getTemplateLib().getInstanceOf("beanEqualsEntry", new STAttrMap().put("fieldName", fieldName));
equalsEntries.add(currentEntry);
}
return getTemplateLib().getInstanceOf("beanEquals", new STAttrMap().put("entries", equalsEntries));
}
@SuppressWarnings("unused")
private StringTemplate getHashCode(Set fieldNames) {
List hashCodeEntries = new LinkedList();
for (String fieldName : fieldNames) {
StringTemplate currentEntry = getTemplateLib().getInstanceOf("beanHashCodeEntry", new STAttrMap().put("fieldName", fieldName));
hashCodeEntries.add(currentEntry);
}
return getTemplateLib().getInstanceOf("beanHashCode", new STAttrMap().put("entries", hashCodeEntries));
}
protected String getPackageAndClass(String typeName) {
String pkg = getPackage(typeName);
return pkg + "." + typeName;
}
private String getPackage(String typeName) {
String pkg = typeToPackage.get(typeName);
if (pkg == null) {
pkg = DEFAULT_PACKAGE;
}
return pkg;
}
/**
* Create a new parser instance, pre-supplying the input token stream.
*
* @param input
* The stream of tokens that will be pulled from the lexer
*/
protected AbstractTTreeDotNet(TreeNodeStream input) {
super(input);
}
/**
* Create a new parser instance, pre-supplying the input token stream and the shared state.
*
* This is only used when a grammar is imported into another grammar, but we must supply this constructor to satisfy the super class contract.
*
* @param input
* The stream of tokesn that will be pulled from the lexer
* @param state
* The shared state object created by an interconnectd grammar
*/
protected AbstractTTreeDotNet(TreeNodeStream input, RecognizerSharedState state) {
super(input, state);
}
/**
* Creates the error/warning message that we need to show users/IDEs when ANTLR has found a parsing error, has recovered from it and is now telling us that
* a parsing exception occurred.
*
* @param tokenNames
* token names as known by ANTLR (which we ignore)
* @param e
* The exception that was thrown
*/
@Override
public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
// This is just a place holder that shows how to override this method
//
super.displayRecognitionError(tokenNames, e);
}
List callNameEntries = new LinkedList();
public void addCallNameEntry(StringTemplate entry) {
callNameEntries.add(entry);
}
public List getCallNameEntries() {
return callNameEntries;
}
List apiNames = new LinkedList();
public void addApiName(String apiName) {
apiNames.add(apiName);
}
public List getApiNames() {
return apiNames;
}
public abstract void setTemplateLib(StringTemplateGroup templates);
public String formatDoc(String raw) {
return raw.replaceAll("@@", "\n").replaceAll("@", "\n@");
}
@Override
public void reportError(RecognitionException e) {
super.reportError(e);
throw new IllegalArgumentException("Failed");
}
/**
* Returns a generated path under build/generated-sources/main/java/rapture for the current file. The path will be slightly different if we have an sdkName
* defined
*
* @param sdkName
* The name of the SDK. If set, then sdkPackage will be appended to this. If null, noSdkPackage will be used instead
* @param sdkPackage
* @param noSdkPackage
* @param constantPart
* This is always appended at the end
* @return
*/
protected String getGeneratedFilePath(String sdkName, String sdkPackage, String noSdkPackage, String constantPart) {
if (sdkName == null) {
return String.format(GENERATED_PATH, constantPart);
} else {
return String.format(GENERATED_PATH, constantPart);
}
}
private static final String GENERATED_PATH = "Generated/%s";
public abstract StringTemplateGroup getTemplateLib();
protected String convertApiName(String apiName) {
if (apiName.equals("Lock")) {
return "Rlock";
} else if (apiName.equals("Event")) {
return "Revent";
}
return apiName;
}
protected String convertFieldName(String fieldName) {
if (fieldName.equals("event")) {
return "revent";
} else if (fieldName.equals("lock")) {
return "rlock";
} else if (fieldName.equals("params")) {
return "rparams";
}
return fieldName;
}
public void processHmxdef(String sdkName, List ents, List kEntries, List kSetups, int major, int minor,
int micro, int minMajor, int minMinor, int minMicro) {
String clientVersionPath = getGeneratedFilePath(sdkName, "client", "client", "ClientApiVersion.cs");
StringTemplate clientVersionVal = getTemplateLib().getInstanceOf(
"versionConst",
new STAttrMap().put("sdkname", sdkName).put("major", major).put("minor", minor).put("micro", micro).put("type", "Client")
.put("packageSuffix", "client"));
addApiTemplate(clientVersionPath, "1", clientVersionVal);
}
@SuppressWarnings("unused")
private void generateSchemeTemplate(String sdkName) {
List fields = generateSchemeFieldTemplates();
StringTemplate schemeTemplate = getTemplateLib().getInstanceOf("scheme", new STAttrMap().put("fields", fields));
String path = getGeneratedFilePath(sdkName, "common", "common", "Scheme.cs");
addApiTemplate(path, "1", schemeTemplate);
}
private List generateSchemeFieldTemplates() {
List list = new LinkedList();
for (Entry entry : schemesMap.entrySet()) {
StringTemplate template = getTemplateLib().getInstanceOf("schemeField",
new STAttrMap().put("name", entry.getKey()).put("isPrimitive", entry.getValue().toString()));
list.add(template);
}
return list;
}
/**
* allows convenient multi-value initialization: "new STAttrMap().put(...).put(...)"
*/
@SuppressWarnings("serial")
public static class STAttrMap extends HashMap {
public STAttrMap put(String attrName, Object value) {
super.put(attrName, value);
return this;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy