esdlcmd_core.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2013 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include <stdio.h>
  14. #include "jlog.hpp"
  15. #include "jfile.hpp"
  16. #include "jargv.hpp"
  17. #include "build-config.h"
  18. #include "esdlcmd_common.hpp"
  19. #include "esdlcmd_core.hpp"
  20. #include "esdl2ecl.cpp"
  21. #include "esdl-publish.cpp"
  22. class Esdl2XSDCmd : public EsdlHelperConvertCmd
  23. {
  24. public:
  25. Esdl2XSDCmd() : optVersion(0), optAllAnnot(false), optNoAnnot(false),
  26. optEnforceOptional(true), optRawOutput(false), optXformTimes(1), optFlags(DEPFLAG_COLLAPSE|DEPFLAG_ARRAYOF),
  27. outfileext(".xsd")
  28. {}
  29. virtual bool parseCommandLineOptions(ArgvIterator &iter)
  30. {
  31. if (iter.done())
  32. {
  33. usage();
  34. return false;
  35. }
  36. //First two parameters' order is fixed.
  37. for (int par = 0; par < 2 && !iter.done(); par++)
  38. {
  39. const char *arg = iter.query();
  40. if (*arg != '-')
  41. {
  42. if (optSource.isEmpty())
  43. optSource.set(arg);
  44. else if (optService.isEmpty())
  45. optService.set(arg);
  46. else
  47. {
  48. fprintf(stderr, "\nunrecognized argument detected before required parameters: %s\n", arg);
  49. usage();
  50. return false;
  51. }
  52. }
  53. else
  54. {
  55. fprintf(stderr, "\noption detected before required parameters: %s\n", arg);
  56. usage();
  57. return false;
  58. }
  59. iter.next();
  60. }
  61. for (; !iter.done(); iter.next())
  62. {
  63. if (parseCommandLineOption(iter))
  64. continue;
  65. if (matchCommandLineOption(iter, true)!=EsdlCmdOptionMatch)
  66. return false;
  67. }
  68. return true;
  69. }
  70. virtual bool parseCommandLineOption(ArgvIterator &iter)
  71. {
  72. if (iter.matchOption(optVersionStr, ESDLOPT_VERSION))
  73. return true;
  74. if (iter.matchOption(optService, ESDLOPT_SERVICE))
  75. return true;
  76. if (iter.matchOption(optMethod, ESDLOPT_METHOD))
  77. return true;
  78. if (iter.matchOption(optXsltPath, ESDLOPT_XSLT_PATH))
  79. return true;
  80. if (iter.matchOption(optPreprocessOutputDir, ESDLOPT_PREPROCESS_OUT))
  81. return true;
  82. if (iter.matchOption(optAnnotate, ESDLOPT_ANNOTATE))
  83. return true;
  84. if (iter.matchOption(optTargetNamespace, ESDLOPT_TARGET_NAMESPACE) || iter.matchOption(optTargetNamespace, ESDLOPT_TARGET_NS))
  85. return true;
  86. if (iter.matchOption(optOptional, ESDLOPT_OPT_PARAM_VAL) || iter.matchOption(optOptional, ESDLOPT_OPTIONAL_PARAM_VAL))
  87. return true;
  88. if (iter.matchFlag(optEnforceOptional, ESDLOPT_NO_OPTIONAL_ATTRIBUTES))
  89. return true;
  90. if (iter.matchOption(optXformTimes, ESDLOPT_NUMBER))
  91. return true;
  92. if (iter.matchFlag(optNoCollapse, ESDLOPT_NO_COLLAPSE))
  93. return true;
  94. if (iter.matchFlag(optNoArrayOf, ESDLOPT_NO_ARRAYOF))
  95. return true;
  96. if (EsdlConvertCmd::parseCommandLineOption(iter))
  97. return true;
  98. return false;
  99. }
  100. esdlCmdOptionMatchIndicator matchCommandLineOption(ArgvIterator &iter, bool finalAttempt)
  101. {
  102. return EsdlConvertCmd::matchCommandLineOption(iter, true);
  103. }
  104. virtual bool finalizeOptions(IProperties *globals)
  105. {
  106. if (optSource.isEmpty())
  107. {
  108. usage();
  109. throw( MakeStringException(0, "\nError: Source esdl parameter required\n"));
  110. }
  111. if( optService.isEmpty() )
  112. {
  113. usage();
  114. throw( MakeStringException(0, "A service name must be provided") );
  115. }
  116. if (!optVersionStr.isEmpty())
  117. {
  118. optVersion = atof( optVersionStr.get() );
  119. if( optVersion <= 0 )
  120. {
  121. throw MakeStringException( 0, "Version option must be followed by a real number > 0" );
  122. }
  123. }
  124. if (optXsltPath.isEmpty())
  125. optXsltPath.set(COMPONENTFILES_DIR);
  126. fullxsltpath.set(optXsltPath);
  127. fullxsltpath.append("/xslt/esxdl2xsd.xslt");
  128. if (!optPreprocessOutputDir.isEmpty())
  129. optRawOutput = true;
  130. if (!optAnnotate.isEmpty())
  131. {
  132. if (strcmp (optAnnotate.get(), "all") ==0)
  133. {
  134. optAllAnnot = true;
  135. }
  136. else if (strcmp (optAnnotate.get(), "none") ==0)
  137. {
  138. optNoAnnot = true;
  139. }
  140. else
  141. {
  142. throw MakeStringException( 0, "--annotate option must be followed by 'all' or 'none' " );
  143. }
  144. }
  145. if (optNoCollapse)
  146. {
  147. unsetFlag(DEPFLAG_COLLAPSE);
  148. }
  149. if(optNoArrayOf)
  150. {
  151. unsetFlag(DEPFLAG_ARRAYOF);
  152. }
  153. if(optTargetNamespace.isEmpty())
  154. {
  155. optTargetNamespace.set(ESDLBINDING_URN_BASE);
  156. }
  157. return true;
  158. }
  159. virtual void doTransform(IEsdlDefObjectIterator& objs, StringBuffer &target, double version=0, IProperties *opts=NULL, const char *ns=NULL, unsigned flags=0 )
  160. {
  161. TimeSection ts("transforming via XSLT");
  162. helper->toXSD( objs, target, EsdlXslToXsd, optVersion, opts, NULL, optFlags );
  163. }
  164. virtual void loadTransform( StringBuffer &xsltpath, IProperties *params)
  165. {
  166. TimeSection ts("loading XSLT");
  167. helper->loadTransform( xsltpath, params, EsdlXslToXsd );
  168. }
  169. virtual void setTransformParams(IProperties *params )
  170. {
  171. helper->setTransformParams(EsdlXslToXsd, params);
  172. }
  173. virtual int processCMD()
  174. {
  175. loadServiceDef();
  176. createOptionals();
  177. Owned<IEsdlDefObjectIterator> structs = esdlDef->getDependencies( optService.get(), optMethod.get(), ESDLOPTLIST_DELIMITER, optVersion, opts.get(), optFlags );
  178. if( optRawOutput )
  179. {
  180. outputRaw(*structs);
  181. }
  182. if( !optXsltPath.isEmpty() )
  183. {
  184. createParams();
  185. loadTransform( fullxsltpath, params);
  186. for( int i=0; i < optXformTimes; i++ )
  187. {
  188. doTransform( *structs, outputBuffer, optVersion, opts.get(), NULL, optFlags );
  189. }
  190. outputToFile();
  191. printf( "%s\n", outputBuffer.str() );
  192. }
  193. else
  194. {
  195. throw( MakeStringException(0, "Path to /xslt/esxdl2xsd.xslt is empty, cannot perform transform.") );
  196. }
  197. return 0;
  198. }
  199. void printOptions()
  200. {
  201. puts("Options:");
  202. puts(" --version <version number> : Constrain to interface version\n");
  203. puts(" --method <method name>[;<method name>]* : Constrain to list of specific method(s)\n" );
  204. puts(" --xslt <xslt file path> : Path to '/xslt/esxdl2xsd.xslt' file to transform EsdlDef to XSD\n" );
  205. puts(" --preprocess-output <raw output directory> : Output pre-processed xml file to specified directory before applying XSLT transform\n" );
  206. puts(" --annotate <all | none> : Flag turning on either all annotations or none. By default annotations are generated " );
  207. puts(" for Enumerations. Setting the flag to 'none' will disable even those. Setting it" );
  208. puts(" to 'all' will enable additional annotations such as collapsed, cols, form_ui, html_head and rows.\n");
  209. puts(" --noopt : Turns off the enforcement of 'optional' attributes on elements. If no -noopt is specified then all elements with an 'optional'" );
  210. puts(" will be included in the output. By default 'optional' filtering is enforced.\n");
  211. puts(" -opt,--optional <param value> : Value to use for optional tag filter when gathering dependencies" );
  212. puts(" An example: passing 'internal' when some Esdl definition objects have the attribute");
  213. puts(" optional(\"internal\") will ensure they appear in the XSD, otherwise they'd be filtered out\n");
  214. puts(" -tns,--target-namespace <target namespace> : The target namespace, passed to the transform via the parameter 'tnsParam'\n" );
  215. puts(" used for the final output of the XSD. If not supplied will default to " );
  216. puts(" http://webservices.seisint.com/<service name>\n" );
  217. puts(" -n <int>: Number of times to run transform after loading XSLT. Defaults to 1.\n" );
  218. puts(" --show-inheritance : Turns off the collapse feature. Collapsing optimizes the XML output to strip out structures\n" );
  219. puts(" only used for inheritance, and collapses their elements into their child. That simplifies the\n" );
  220. puts(" stylesheet. By default this option is on.");
  221. puts(" --no-arrayof : Supresses the use of the arrrayof element. arrayof optimizes the XML output to include 'ArrayOf...'\n" );
  222. puts(" structure definitions for those EsdlArray elements with no item_tag attribute. Works in conjuction\n" );
  223. puts(" with an optimized stylesheet that doesn't generate these itself. This defaults to on.");
  224. }
  225. virtual void usage()
  226. {
  227. puts("Usage:");
  228. puts("esdl xsd sourcePath serviceName [options]\n" );
  229. puts("\nsourcePath must be absolute path to the ESDL Definition file containing the" );
  230. puts("EsdlService definition for the service you want to work with.\n" );
  231. puts("serviceName EsdlService definition for the service you want to work with.\n" );
  232. printOptions();
  233. EsdlConvertCmd::usage();
  234. }
  235. virtual void outputRaw( IEsdlDefObjectIterator& obj)
  236. {
  237. if( optRawOutput )
  238. {
  239. StringBuffer xmlOut;
  240. StringBuffer empty;
  241. xmlOut.appendf( "<esxdl name=\"%s\">", optService.get());
  242. helper->toXML( obj, xmlOut, optVersion, opts.get(), optFlags );
  243. xmlOut.append("</esxdl>");
  244. saveAsFile( optPreprocessOutputDir.get(), empty, xmlOut.str(), NULL );
  245. }
  246. }
  247. virtual void createOptionals()
  248. {
  249. // 09jun2011 tja: We must ensure that the opts IProperties object is
  250. // valid/non-null. This is because by passing null/invalid in to the
  251. // getDependencies call we're indicating that we want to turn off
  252. // optional filtering.
  253. if( optEnforceOptional )
  254. {
  255. opts.setown(createProperties(false));
  256. if( optOptional.length() )
  257. {
  258. opts->setProp(optOptional.get(), 1);
  259. }
  260. }
  261. }
  262. void createParams()
  263. {
  264. params.set(createProperties());
  265. generateNamespace(tns);
  266. params->setProp( "tnsParam", tns );
  267. params->setProp( "optional", optOptional );
  268. if( optAllAnnot )
  269. {
  270. params->setProp( "all_annot_Param", 1 );
  271. }
  272. if( optNoAnnot )
  273. {
  274. params->setProp( "no_annot_Param", 1 );
  275. }
  276. }
  277. virtual void loadServiceDef()
  278. {
  279. serviceDef.setown( createIFile(optSource) );
  280. if( serviceDef->exists() )
  281. {
  282. if( serviceDef->isFile() )
  283. {
  284. if( serviceDef->size() > 0 )
  285. {
  286. // Realized a subtle source of potential problems. Because there
  287. // can be multiple EsdlStruct definitions with the same name
  288. // in multiple files, you need to be careful that only those files
  289. // explicitly included by your service are loaded to the
  290. // EsdlDefinition object that you'll getDependencies() on. If not,
  291. // you could inadvertently getDependencies() from a different structure
  292. // with the same name. This means we can only reliably process one
  293. // Web Service at a time, and must load files by explicitly loading
  294. // only the top-level ws_<service> definition file, and allowing the
  295. // load code to handle loading only the minimal set of required includes
  296. esdlDef->addDefinitionsFromFile( serviceDef->queryFilename() );
  297. }
  298. else
  299. {
  300. throw( MakeStringException(0, "ESDL definition file source %s is empty", optSource.get()) );
  301. }
  302. }
  303. else
  304. {
  305. throw( MakeStringException(0, "ESDL definition file source %s is not a file", optSource.get()) );
  306. }
  307. }
  308. else
  309. {
  310. throw( MakeStringException(0, "ESDL definition file source %s does not exist", optSource.get()) );
  311. }
  312. }
  313. virtual void outputToFile()
  314. {
  315. if (!optOutDirPath.isEmpty())
  316. {
  317. StringBuffer filename;
  318. generateOutputFileName(filename);
  319. saveAsFile(optOutDirPath.get(), filename, outputBuffer.str(), NULL);
  320. }
  321. }
  322. StringBuffer & generateNamespace(StringBuffer &ns)
  323. {
  324. ns.appendf("%s:%s", optTargetNamespace.get(), optService.get());
  325. //only add methodname if single method used.
  326. if (!optMethod.isEmpty() && !strstr(optMethod.get(), ESDLOPTLIST_DELIMITER))
  327. ns.append(':').append(optMethod.get());
  328. //todo
  329. /*
  330. StringBuffer ns_optionals;
  331. //IProperties *params = context.queryRequestParameters();
  332. Owned<IPropertyIterator> esdl_optionals = esdlDef->queryOptionals()->getIterator();
  333. ForEach(*esdl_optionals)
  334. {
  335. const char *key = esdl_optionals->getPropKey();
  336. if (params->hasProp(key))
  337. {
  338. if (ns_optionals.length())
  339. ns_optionals.append(',');
  340. ns_optionals.append(key);
  341. }
  342. }
  343. if (ns_optionals.length())
  344. ns.append('(').append(ns_optionals.str()).append(')');
  345. */
  346. if (optVersion > 0)
  347. ns.append("@ver=").appendf("%g", optVersion);
  348. return ns.toLowerCase();
  349. }
  350. virtual StringBuffer & generateOutputFileName( StringBuffer &filename)
  351. {
  352. filename.appendf("%s", optService.get());
  353. if (!optMethod.isEmpty() && !strstr(optMethod.get(), ESDLOPTLIST_DELIMITER))
  354. filename.append('-').append(optMethod.get());
  355. filename.append(outfileext);
  356. return filename.toLowerCase();
  357. }
  358. void saveAsFile(const char * dir, StringBuffer &outname, const char *text, const char *ext="")
  359. {
  360. StringBuffer path(dir);
  361. if( outname.length()>0 && path.charAt(path.length()) != PATHSEPCHAR && outname.charAt(0) != PATHSEPCHAR)
  362. {
  363. path.append(PATHSEPCHAR);
  364. path.append(outname);
  365. }
  366. if( ext && *ext )
  367. {
  368. path.append(ext);
  369. }
  370. Owned<IFile> file = createIFile(path.str());
  371. Owned<IFileIO> io;
  372. io.setown(file->open(IFOcreaterw));
  373. DBGLOG("Writing to file %s", file->queryFilename());
  374. if (io.get())
  375. io->write(0, strlen(text), text);
  376. else
  377. DBGLOG("File %s can't be created", file->queryFilename());
  378. }
  379. void setFlag( unsigned f ) { optFlags |= f; }
  380. void unsetFlag( unsigned f ) { optFlags &= ~f; }
  381. public:
  382. StringAttr optService;
  383. StringAttr optXsltPath;
  384. StringAttr optMethod;
  385. StringAttr optOptional;
  386. bool optEnforceOptional;
  387. StringAttr optAnnotate;
  388. bool optAllAnnot, optNoAnnot;
  389. StringAttr optTargetNamespace;
  390. StringAttr optPreprocessOutputDir;
  391. bool optRawOutput;
  392. StringAttr optVersionStr;
  393. double optVersion;
  394. unsigned int optXformTimes;
  395. unsigned optFlags;
  396. bool optNoCollapse;
  397. bool optNoArrayOf;
  398. protected:
  399. Owned<IFile> serviceDef;
  400. StringBuffer outputBuffer;
  401. StringBuffer fullxsltpath;
  402. Owned<IProperties> opts;
  403. Owned<IProperties> params;
  404. StringBuffer tns;
  405. StringBuffer outfileext;
  406. };
  407. class Esdl2WSDLCmd : public Esdl2XSDCmd
  408. {
  409. public:
  410. Esdl2WSDLCmd()
  411. {
  412. outfileext.set(".wsdl");
  413. }
  414. virtual bool parseCommandLineOption(ArgvIterator &iter)
  415. {
  416. if (iter.matchFlag(optWsdlAddress, ESDLOPT_WSDL_ADDRESS))
  417. return true;
  418. if (Esdl2XSDCmd::parseCommandLineOption(iter))
  419. return true;
  420. return false;
  421. }
  422. esdlCmdOptionMatchIndicator matchCommandLineOption(ArgvIterator &iter, bool finalAttempt)
  423. {
  424. return Esdl2XSDCmd::matchCommandLineOption(iter, true);
  425. }
  426. virtual bool finalizeOptions(IProperties *globals)
  427. {
  428. if (optWsdlAddress.isEmpty())
  429. optWsdlAddress.set("localhost");
  430. return Esdl2XSDCmd::finalizeOptions(globals);
  431. }
  432. virtual void doTransform(IEsdlDefObjectIterator& objs, StringBuffer &target, double version=0, IProperties *opts=NULL, const char *ns=NULL, unsigned flags=0 )
  433. {
  434. TimeSection ts("transforming via XSLT");
  435. helper->toWSDL(objs, target, EsdlXslToWsdl, optVersion, opts, NULL, optFlags);
  436. }
  437. virtual void loadTransform( StringBuffer &xsltpath, IProperties *params)
  438. {
  439. TimeSection ts("loading XSLT");
  440. helper->loadTransform( xsltpath, params, EsdlXslToWsdl );
  441. }
  442. virtual void setTransformParams(IProperties *params )
  443. {
  444. helper->setTransformParams(EsdlXslToWsdl, params);
  445. }
  446. virtual int processCMD()
  447. {
  448. loadServiceDef();
  449. createOptionals();
  450. Owned<IEsdlDefObjectIterator> structs = esdlDef->getDependencies( optService.get(), optMethod.get(), ESDLOPTLIST_DELIMITER, optVersion, opts.get(), optFlags );
  451. if( optRawOutput )
  452. {
  453. outputRaw(*structs);
  454. }
  455. if( !optXsltPath.isEmpty() )
  456. {
  457. createParams();
  458. loadTransform( fullxsltpath, params);
  459. for( int i=0; i < optXformTimes; i++ )
  460. {
  461. doTransform( *structs, outputBuffer, optVersion, opts.get(), NULL, optFlags );
  462. }
  463. outputToFile();
  464. printf( "%s\n", outputBuffer.str() );
  465. }
  466. else
  467. {
  468. throw( MakeStringException(0, "Path to /xslt/esxdl2xsd.xslt is empty, cannot perform transform.") );
  469. }
  470. return 0;
  471. }
  472. virtual void usage()
  473. {
  474. puts("Usage:");
  475. puts("esdl wsdl sourcePath serviceName [options]\n" );
  476. puts("\nsourcePath must be absolute path to the ESDL Definition file containing the" );
  477. puts("EsdlService definition for the service you want to work with.\n" );
  478. puts("serviceName EsdlService definition for the service you want to work with.\n" );
  479. printOptions();
  480. puts(" --wsdladdress Defines the output WSDL's location address\n");
  481. EsdlConvertCmd::usage();
  482. }
  483. virtual void createParams()
  484. {
  485. params.set(createProperties());
  486. generateNamespace(tns);
  487. params->setProp( "tnsParam", tns );
  488. params->setProp( "optional", optOptional );
  489. if( optAllAnnot )
  490. {
  491. params->setProp( "all_annot_Param", 1 );
  492. }
  493. if( optNoAnnot )
  494. {
  495. params->setProp( "no_annot_Param", 1 );
  496. }
  497. params->setProp( "create_wsdl", "true()" );
  498. params->setProp( "location", optWsdlAddress.get());
  499. }
  500. public:
  501. StringAttr optWsdlAddress;
  502. };
  503. //=========================================================================================
  504. IEsdlCommand *createCoreEsdlCommand(const char *cmdname)
  505. {
  506. if (!cmdname || !*cmdname)
  507. return NULL;
  508. if (strieq(cmdname, "XSD"))
  509. return new Esdl2XSDCmd();
  510. if (strieq(cmdname, "ECL"))
  511. return new Esdl2EclCmd();
  512. if (strieq(cmdname, "WSDL"))
  513. return new Esdl2WSDLCmd();
  514. if (strieq(cmdname, "PUBLISH"))
  515. return new EsdlPublishCmd();
  516. if (strieq(cmdname, "DELETE"))
  517. return new EsdlDeleteESDLDefCmd();
  518. if (strieq(cmdname, "BIND-SERVICE"))
  519. return new EsdlBindServiceCmd();
  520. if (strieq(cmdname, "BIND-METHOD"))
  521. return new EsdlBindMethodCmd();
  522. if (strieq(cmdname, "GET-BINDING"))
  523. return new EsdlGetBindingCmd();
  524. if (strieq(cmdname, "GET-DEFINITION"))
  525. return new EsdlGetDefinitionCmd();
  526. if (strieq(cmdname, "UNBIND-SERVICE"))
  527. return new EsdlUnBindServiceCmd();
  528. if (strieq(cmdname, "LIST-DEFINITIONS"))
  529. return new EsdlListESDLDefCmd();
  530. if (strieq(cmdname, "LIST-BINDINGS"))
  531. return new EsdlListESDLBindingsCmd();
  532. return NULL;
  533. }