| /* |
| * 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. |
| */ |
| |
| #include "../base_types.hpp" |
| #include "../InputParserFactory.hpp" |
| #include "../CodeGeneratorFactory.hpp" |
| #include "../CodeGenerator.hpp" |
| #include "Log.hpp" |
| #include "Helper.hpp" |
| #include <iostream> |
| |
| /** |
| * @namespace apache::geode::client::pdx_auto_serializer The namespace containing |
| * the |
| * auto-serializer classes. |
| */ |
| using namespace apache::geode::client::pdx_auto_serializer; |
| |
| /** The name used for invocation of the program on command-line. */ |
| std::string progName; |
| /** The parser factory object. */ |
| InputParserFactory parserFactory; |
| /** The code generator factory object. */ |
| CodeGeneratorFactory generatorFactory; |
| /** The parser returned by the parser factory. */ |
| InputParser* parser = NULL; |
| /** The list of classes given by the parser. */ |
| ASClassVector classes; |
| /** The <code>CodeGenerator</code> object returned by the factory. */ |
| CodeGenerator* codeGenerator = NULL; |
| /** |
| * The options with their usage for the tool with current parser and |
| * code generator. |
| */ |
| OptionMap toolOptions; |
| |
| /** Name of this module. */ |
| static std::string ModuleName = "PdxAutoSerializer"; |
| |
| /** |
| * The option used to specify the language of the code to be auto-serialized. |
| */ |
| static const std::string LanguageOption = "language"; |
| |
| /** |
| * The option used to specify the language in which the auto-serialized code |
| * is to be generated. |
| */ |
| static const std::string GeneratorOption = "generator"; |
| |
| /** The option name for class name. */ |
| static const std::string ClassNameOption = "className"; |
| |
| /** The option name for class name String */ |
| static const std::string getClassNameOption = "classNameStr"; |
| |
| /** The option used to obtain usage information. */ |
| static const std::string UsageOption = "usage"; |
| |
| /** The option for help -- gives same output as usage for now. */ |
| static const std::string HelpOption = "help"; |
| |
| /** the option for directory to generate auto-generated files */ |
| static const std::string outDirectoryOption = "outDir"; |
| |
| /** Fill in the default top-level options required for the tool. */ |
| void addMainOptions(); |
| |
| /** |
| * Parse the command-line and get the resource names and the properties. |
| * |
| * @param argc The number of command-line arguments. |
| * @param argv The string array containing the command-line arguments. |
| * @param resources The names of the resources. |
| * @param properties Output parameter containing the properties as a map. |
| */ |
| void parseCommandLine(int argc, char** argv, StringVector& resources, |
| PropertyMap& properties); |
| |
| /** |
| * Show the program usage. If any language/generator has been selected then |
| * its options are also shown. |
| */ |
| void showUsage(); |
| |
| /** Cleanly destroy all the global objects. */ |
| void cleanupObjects(); |
| |
| /** Cleanup any files or other artifacts in case of abnormal exit. */ |
| void cleanup(); |
| |
| /** |
| * The main entry point of the tool. |
| * |
| * @param argc The number of command-line arguments. |
| * @param argv The string array containing the command-line arguments. |
| */ |
| |
| static void Tokenize(const std::string& str, std::vector<std::string>& tokens, |
| const std::string& delimiters = " ") { |
| std::string::size_type lastPos = str.find_first_not_of(delimiters, 0); |
| std::string::size_type pos = str.find_first_of(delimiters, lastPos); |
| while (std::string::npos != pos || std::string::npos != lastPos) { |
| tokens.push_back(str.substr(lastPos, pos - lastPos)); |
| lastPos = str.find_first_not_of(delimiters, pos); |
| pos = str.find_first_of(delimiters, lastPos); |
| } |
| } |
| int main(int argc, char** argv) { |
| bool success = false; |
| struct CleanUp { |
| private: |
| bool& m_success; |
| |
| public: |
| explicit CleanUp(bool& success) : m_success(success) {} |
| ~CleanUp() { |
| if (m_success) { |
| cleanupObjects(); |
| } else { |
| cleanup(); |
| } |
| } |
| } cleanOnExit(success); |
| |
| try { |
| StringVector resources; |
| PropertyMap properties; |
| const std::string languageString = "C++"; |
| const std::string generatorString = "C++"; |
| StringVector classNames; |
| |
| progName = argv[0]; |
| std::string::size_type baseIndex = progName.find_last_of("/\\"); |
| if (baseIndex != std::string::npos) { |
| progName = progName.substr(baseIndex + 1); |
| } |
| addMainOptions(); |
| parseCommandLine(argc, argv, resources, properties); |
| std::map<std::string, std::string> classNameStringMap; |
| |
| try { |
| if (languageString.length() > 0 && |
| (parser = parserFactory.getInstance(languageString)) == NULL) { |
| throw std::invalid_argument("No such language: " + languageString); |
| } |
| |
| if (generatorString.length() > 0 && |
| (codeGenerator = generatorFactory.getInstance(generatorString)) == |
| NULL) { |
| throw std::invalid_argument("No such code generator: " + |
| generatorString); |
| } |
| |
| if (parser != NULL) { |
| parser->getOptions(toolOptions); |
| } |
| if (codeGenerator != NULL) { |
| codeGenerator->getOptions(toolOptions); |
| } |
| |
| std::string usageString; |
| if (Helper::getSingleProperty(properties, UsageOption, usageString) || |
| Helper::getSingleProperty(properties, HelpOption, usageString)) { |
| showUsage(); |
| return 0; |
| } |
| |
| if (parser == NULL) { |
| throw std::invalid_argument("No input language specified."); |
| } |
| if (codeGenerator == NULL) { |
| throw std::invalid_argument("No output language specified."); |
| } |
| if (resources.size() == 0) { |
| throw std::invalid_argument("No input resources specified."); |
| } |
| |
| if (!Helper::getMultiProperty(properties, ClassNameOption, classNames) || |
| classNames.size() == 0) { |
| Log::warn(ModuleName, |
| "No class name specified; " |
| "will serialize all classes."); |
| } |
| |
| std::string classNameString; |
| |
| std::vector<std::string> classNameStringVector; |
| |
| Helper::getMultiProperty(properties, getClassNameOption, |
| classNameStringVector); |
| for (std::vector<std::string>::iterator itr = |
| classNameStringVector.begin(); |
| itr != classNameStringVector.end(); ++itr) { |
| std::vector<std::string> eachClassNameVector; |
| Tokenize(*itr, eachClassNameVector, ":"); |
| if (eachClassNameVector.size() == 2) { |
| classNameStringMap.insert(std::pair<std::string, std::string>( |
| eachClassNameVector[0], eachClassNameVector[1])); |
| } else { |
| throw std::invalid_argument("No input class name string specified."); |
| } |
| } |
| |
| parser->init(properties); |
| parser->selectClasses(resources, classNames); |
| parser->getSelectedClasses(classes); |
| |
| codeGenerator->init(properties); |
| |
| } catch (const std::exception& ex) { |
| std::cerr << Helper::typeName(ex) << ": " << ex.what() << std::endl; |
| std::cerr << "Use --help or --usage option for help" << std::endl; |
| return 1; |
| } |
| |
| if (properties.size() > 0) { |
| showUsage(); |
| return 1; |
| } |
| |
| Log::info(ModuleName, "Classes being serialized:"); |
| for (ASClassVector::const_iterator classIterator = classes.begin(); |
| classIterator != classes.end(); ++classIterator) { |
| Log::info(ModuleName, '\t' + (*classIterator)->getName()); |
| } |
| |
| for (ASClassVector::const_iterator classIterator = classes.begin(); |
| classIterator != classes.end(); ++classIterator) { |
| ReferenceVector references; |
| TypeInfo classInfo; |
| VariableVector members; |
| std::string varName = "__var"; |
| |
| const ClassInfo* currentClass = *classIterator; |
| |
| try { |
| currentClass->getTypeInfo(classInfo); |
| codeGenerator->initClass(classInfo); |
| } catch (const std::exception& ex) { |
| std::cerr << Helper::typeName(ex) << ": " << ex.what() << std::endl; |
| std::cerr << "Use --help or --usage option for help" << std::endl; |
| return 1; |
| } |
| |
| currentClass->getReferences(references); |
| currentClass->getMembers(members); |
| |
| codeGenerator->addFileHeader(argc, argv); |
| codeGenerator->addReferences(references); |
| codeGenerator->startClass(members); |
| |
| std::vector<CodeGenerator::Method::Type> methods; |
| methods.push_back(CodeGenerator::Method::TODATA); |
| methods.push_back(CodeGenerator::Method::FROMDATA); |
| for (size_t index = 0; index < methods.size(); ++index) { |
| CodeGenerator::Method::Type method = methods[index]; |
| codeGenerator->startMethod(method, varName, |
| currentClass->getMethodPrefix()); |
| // Adding try block |
| // Ticket #905 Changes starts here |
| codeGenerator->addTryBlockStart(method); |
| // Ticket #905 Changes ends here |
| for (VariableVectorIterator memberIterator = members.begin(); |
| memberIterator != members.end(); ++memberIterator) { |
| codeGenerator->genMethod(method, varName, *memberIterator); |
| } |
| // Finish try block |
| // Ticket #905 Changes starts here |
| codeGenerator->finishTryBlock(method); |
| // Ticket #905 Changes ends here |
| codeGenerator->endMethod(method, varName); |
| } |
| codeGenerator->genClassNameMethod(classNameStringMap, |
| currentClass->getMethodPrefix()); |
| codeGenerator->genCreateDeserializable(currentClass->getMethodPrefix()); |
| codeGenerator->genTypeId(currentClass->getMethodPrefix()); |
| codeGenerator->endClass(); |
| } |
| } catch (const std::invalid_argument& ex) { |
| std::cerr << "Use --help or --usage option for help" << std::endl; |
| return 1; |
| } catch (const std::exception& ex) { |
| std::cerr << Helper::typeName(ex) << ": " << ex.what() << std::endl; |
| return 1; |
| } catch (...) { |
| std::cerr << "Caught an unknown exception." << std::endl; |
| return 1; |
| } |
| success = true; |
| return 0; |
| } |
| |
| void addMainOptions() { |
| std::pair<bool, std::string> optionPair; |
| // std::string languageStr; |
| // StringVector languages = parserFactory.getParsers(); |
| // assert(languages.size() > 0); |
| // StringVectorIterator languageIterator = languages.begin(); |
| // languageStr = *languageIterator; |
| // while (++languageIterator != languages.end()) { |
| // languageStr += ',' + *languageIterator; |
| //} |
| // optionPair.first = true; |
| ///*optionPair.second = "Generate code for the given language " |
| // "-- one of " + languageStr + " (SINGLE)"; |
| // toolOptions[LanguageOption] = optionPair;*/ |
| |
| // std::string generatorStr; |
| // StringVector generators = generatorFactory.getGenerators(); |
| // assert(generators.size() > 0); |
| // StringVectorIterator generatorIterator = generators.begin(); |
| // generatorStr = *generatorIterator; |
| // while (++generatorIterator != generators.end()) { |
| // generatorStr += ',' + *generatorIterator; |
| //} |
| /*optionPair.second = "Generate code in the given generator " |
| "-- one of " + generatorStr + " (SINGLE)"; |
| toolOptions[GeneratorOption] = optionPair;*/ |
| |
| optionPair.first = true; |
| optionPair.second = |
| "Name of the class for which to generate " |
| "auto-serialization code (MULTIPLE,OPTIONAL)"; |
| toolOptions[ClassNameOption] = optionPair; |
| |
| optionPair.first = false; |
| optionPair.second = (std::string) "\t\tThis usage message."; |
| toolOptions[UsageOption] = optionPair; |
| |
| optionPair.first = false; |
| optionPair.second = (std::string) "\t\tThis help message."; |
| toolOptions[HelpOption] = optionPair; |
| |
| optionPair.first = true; |
| optionPair.second = (std::string) "Name of the class in string representation" |
| "(MULTIPLE,OPTIONAL)"; |
| toolOptions[getClassNameOption] = optionPair; |
| |
| optionPair.first = false; |
| optionPair.second = (std::string) "\tName of the directory where auto-generated" |
| "files will be written, default is current working directory"; |
| toolOptions[outDirectoryOption] = optionPair; |
| } |
| |
| void parseCommandLine(int argc, char** argv, StringVector& resources, |
| PropertyMap& properties) { |
| if (argc < 2) { |
| throw std::invalid_argument(""); |
| } |
| for (int propertyIndex = 1; propertyIndex < argc; propertyIndex++) { |
| char* arg = argv[propertyIndex]; |
| if (arg[0] == '-' && arg[1] == '-') { |
| // Is a property value option. |
| std::string prop = arg + 2; |
| std::string propertyName; |
| std::string propertyValue; |
| std::string::size_type valPos; |
| if ((valPos = prop.find('=')) != std::string::npos) { |
| propertyName = prop.substr(0, valPos); |
| propertyValue = prop.substr(valPos + 1); |
| } else { |
| propertyName = prop; |
| } |
| PropertyMap::iterator propertyFind = properties.find(propertyName); |
| if (propertyFind == properties.end()) { |
| StringVector propertyValues; |
| if (propertyValue.length() > 0) { |
| propertyValues.push_back(propertyValue); |
| } |
| properties[propertyName] = propertyValues; |
| } else if (propertyValue.length() > 0) { |
| propertyFind->second.push_back(propertyValue); |
| } |
| } else { |
| resources.push_back(arg); |
| } |
| } |
| } |
| |
| void showUsage() { |
| std::cout << "Usage: " << progName << " [OPTIONS] <resources e.g. " |
| "header> ...\n\n"; |
| |
| std::cout << "Resource name should be the path to the header " |
| "containing the classes to be auto-serialized.\n\n"; |
| std::cout |
| << "Options may be one of those given below.\nSINGLE denotes " |
| "that the option should be specified only once.\nMULTIPLE denotes " |
| "that the " |
| "option can be specified more than once.\nOPTIONAL denotes that the " |
| "option may be skipped in which case the default for that shall be " |
| "chosen."; |
| std::cout << '\n' << std::endl; |
| for (OptionMap::const_iterator optionIterator = toolOptions.begin(); |
| optionIterator != toolOptions.end(); ++optionIterator) { |
| std::cout << "--" << optionIterator->first; |
| if (optionIterator->second.first) { |
| std::cout << "=VALUE"; |
| } |
| std::cout << '\t' << optionIterator->second.second << '\n'; |
| } |
| std::cout << std::endl; |
| |
| std::cout << "Examples:" << std::endl; |
| std::cout << "\t pdxautoserializer -outDir=<DIR NAME> <RESOURCE>" |
| << std::endl; |
| std::cout |
| << "\t pdxautoserializer -outDir=<DIR NAME> --className=<CLASSNAME1> "; |
| std::cout << "--className=<CLASSNAME2> <RESOURCE>" << std::endl; |
| std::cout << "\t pdxautoserializer -outDir=<DIR NAME> " |
| "--classNameStr=<CLASSNAME1:User defined String> "; |
| std::cout << "--classNameStr=<CLASSNAME:User defined String> <RESOURCE>" |
| << std::endl |
| << std::endl; |
| std::cout << "Helper Macros to be defined in Input Header File : " |
| << std::endl; |
| std::cout << "GFINCLUDE\t for including a specific member for serialization" |
| << std::endl; |
| std::cout << "GFEXCLUDE\t for excluding a specific member for serialization" |
| << std::endl; |
| std::cout << "GFID\t\t for considering a member as Identify Field" |
| << std::endl; |
| std::cout << "GFARRAYSIZE\t for specifying a array length member" |
| << std::endl; |
| std::cout << "GFIGNORE\t for ignoring certain keywords" << std::endl; |
| std::cout << "For more details refer to documentation on this utility." |
| << std::endl; |
| } |
| |
| void cleanupObjects() { |
| Helper::deleteASClasses(classes); |
| if (parser != NULL) { |
| delete parser; |
| parser = NULL; |
| } |
| if (codeGenerator != NULL) { |
| delete codeGenerator; |
| codeGenerator = NULL; |
| } |
| } |
| |
| void cleanup() { |
| if (codeGenerator != NULL) { |
| codeGenerator->cleanup(); |
| } |
| cleanupObjects(); |
| } |