PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/ojc-core/encodersl/encoder-coco/src/com/sun/encoder/coco/xsdbuilder/CocoXsdBuilder.java

https://bitbucket.org/pymma/openesb-components
Java | 603 lines | 398 code | 59 blank | 146 comment | 53 complexity | 8b62bb69470271a9c6079c77a17b9bc6 MD5 | raw file
  1. /*
  2. * BEGIN_HEADER - DO NOT EDIT
  3. *
  4. * The contents of this file are subject to the terms
  5. * of the Common Development and Distribution License
  6. * (the "License"). You may not use this file except
  7. * in compliance with the License.
  8. *
  9. * You can obtain a copy of the license at
  10. * https://open-jbi-components.dev.java.net/public/CDDLv1.0.html.
  11. * See the License for the specific language governing
  12. * permissions and limitations under the License.
  13. *
  14. * When distributing Covered Code, include this CDDL
  15. * HEADER in each file and include the License file at
  16. * https://open-jbi-components.dev.java.net/public/CDDLv1.0.html.
  17. * If applicable add the following below this CDDL HEADER,
  18. * with the fields enclosed by brackets "[]" replaced with
  19. * your own identifying information: Portions Copyright
  20. * [year] [name of copyright owner]
  21. */
  22. /*
  23. * @(#)CocoXsdBuilder.java
  24. *
  25. * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
  26. *
  27. * END_HEADER - DO NOT EDIT
  28. */
  29. package com.sun.encoder.coco.xsdbuilder;
  30. import java.io.File;
  31. import java.io.FileOutputStream;
  32. import java.io.IOException;
  33. import java.io.PrintStream;
  34. import java.net.URI;
  35. import java.net.URISyntaxException;
  36. import java.util.Collections;
  37. import java.util.HashMap;
  38. import java.util.Map;
  39. import javax.xml.namespace.QName;
  40. import org.apache.xmlbeans.XmlCursor;
  41. import org.apache.xmlbeans.XmlOptions;
  42. import org.apache.xmlbeans.impl.xb.xsdschema.Element;
  43. import org.apache.xmlbeans.impl.xb.xsdschema.Group;
  44. import org.apache.xmlbeans.impl.xb.xsdschema.LocalComplexType;
  45. import org.apache.xmlbeans.impl.xb.xsdschema.SchemaDocument;
  46. import org.apache.xmlbeans.impl.xb.xsdschema.AppinfoDocument.Appinfo;
  47. import org.apache.xmlbeans.impl.xb.xsdschema.SchemaDocument.Schema;
  48. import org.apache.xmlbeans.impl.xb.xsdschema.FormChoice.Enum;
  49. import com.sun.encoder.coco.CocoEncoderProvider;
  50. import com.sun.encoder.coco.appinfo.CocoEncoding;
  51. import com.sun.encoder.coco.appinfo.CocoEncodingMark;
  52. import com.sun.encoder.coco.appinfo.CocoEncoding.OccursDependOn;
  53. import com.sun.encoder.coco.model.CocoDataModel;
  54. import com.sun.encoder.coco.model.CocoDescriptionEntry;
  55. import com.sun.encoder.coco.model.CocoLexer;
  56. import com.sun.encoder.coco.model.CocoParser;
  57. import com.sun.encoder.coco.runtime.messages.ErrorManager;
  58. import com.sun.encoder.coco.runtime.messages.Message;
  59. import com.sun.encoder.coco.runtime.messages.MessageCatalog;
  60. import com.sun.encoder.frmwk.appinfo.EncodingMark.Encoding;
  61. /**
  62. * COBOL Copybook - XSD builder implementation.
  63. *
  64. * @author Noel Ang, Jun Xu
  65. * @version $Revision: 1.6 $
  66. */
  67. public class CocoXsdBuilder {
  68. /**
  69. * Builder version, embedded in generated XSDs
  70. */
  71. public static final String BUILDER_VERSION;
  72. static {
  73. String ver = "$Revision: 1.6 $";
  74. int pos1 = ver.lastIndexOf(':') + 2;
  75. int pos2 = ver.lastIndexOf('$') - 1;
  76. if (pos1 < pos2) {
  77. ver = ver.substring(pos1, pos2).trim();
  78. }
  79. BUILDER_VERSION = ver;
  80. }
  81. private static final boolean mShowTrace =
  82. "true".equals(System.getProperty("sun.encoder.coco.showtrace"));
  83. private CocoXsdBuilderSpec mSpec;
  84. private File mCopybookFile;
  85. private String mCopybookCharEncoding;
  86. private File mXsdFile;
  87. private String mTargetNamespace;
  88. private boolean mIgnoreExtraContent;
  89. private boolean mCheckReservedWord;
  90. private String mDisplayCharEncoding;
  91. private String mDisplay1CharEncoding;
  92. private final Map<CocoDescriptionEntry, SchemaNode> mEntriesToNodes;
  93. private final ErrorManager mErrorMgr =
  94. ErrorManager.getManager("OpenESB.encoder.COBOLCopybook."
  95. + getClass().getName());
  96. /**
  97. * Create COBOL Copybook - XSD builder instance
  98. */
  99. public CocoXsdBuilder() {
  100. mCopybookFile = null;
  101. mXsdFile = null;
  102. mTargetNamespace = null;
  103. mSpec = null;
  104. mEntriesToNodes = Collections.synchronizedMap(
  105. new HashMap<CocoDescriptionEntry, SchemaNode>(10000));
  106. }
  107. /**
  108. * Create COBOL Copybook - XSD builder instance
  109. *
  110. * @param spec Builder Spec {@link CocoXsdBuilderSpec context}
  111. */
  112. public CocoXsdBuilder(CocoXsdBuilderSpec spec) {
  113. mCopybookFile = null;
  114. mXsdFile = null;
  115. mTargetNamespace = null;
  116. validateSpec(spec);
  117. mSpec = spec;
  118. mEntriesToNodes = Collections.synchronizedMap(
  119. new HashMap<CocoDescriptionEntry, SchemaNode>(10000));
  120. }
  121. /**
  122. * Set builder context.
  123. *
  124. * @param spec context
  125. */
  126. public void setOtdBuilderSpec(CocoXsdBuilderSpec spec) {
  127. validateSpec(spec);
  128. mSpec = (CocoXsdBuilderSpec) spec;
  129. }
  130. /**
  131. * Retrieve builder context.
  132. *
  133. * @return CocoXsdBuilderSpec context object associated with builder
  134. */
  135. public CocoXsdBuilderSpec getOtdBuilderSpec() {
  136. return mSpec;
  137. }
  138. /**
  139. * Check context for correctness. If a correctable datum is found, it is
  140. * corrected quietly and no exception is thrown.
  141. *
  142. * @param spec context in consideration
  143. *
  144. * @throws java.lang.IllegalArgumentException if context fails to validate
  145. */
  146. private void validateSpec(CocoXsdBuilderSpec spec)
  147. throws IllegalArgumentException {
  148. Message msg;
  149. String text;
  150. if (spec == null) {
  151. return;
  152. }
  153. /* COBOL Copybook input: non-null; must exist; must be readable file */
  154. String copybookLocation = spec.getCopybookLocation();
  155. if (copybookLocation == null) {
  156. msg = MessageCatalog.getMessage("CCCB4012");
  157. text = msg.toString();
  158. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  159. throw new IllegalArgumentException(text);
  160. }
  161. File copybookFile = new File(copybookLocation);
  162. if (!copybookFile.canRead() || !copybookFile.isFile()) {
  163. msg = MessageCatalog.getMessage("CCCB4015");
  164. text = msg.formatText(new Object[]{copybookFile.getAbsolutePath()});
  165. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  166. throw new IllegalArgumentException(text);
  167. }
  168. /* COBOL Copybook file encoding: non-null */
  169. String copybookEncoding = spec.getCopybookCharEncoding();
  170. if (copybookEncoding == null) {
  171. msg = MessageCatalog.getMessage("CCCB4013");
  172. text = msg.toString();
  173. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  174. throw new IllegalArgumentException(text);
  175. }
  176. /* XSD file location: must not be null. Must a valid file path */
  177. String xsdLocation = spec.getXsdLocation();
  178. if (xsdLocation == null) {
  179. msg = MessageCatalog.getMessage("CCCB4014");
  180. text = msg.toString();
  181. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  182. throw new IllegalArgumentException(text);
  183. }
  184. /* XSD target namespace: might be null, otherwise must be a valid URI */
  185. String targetNamespace = spec.getTargetNamespace();
  186. if (targetNamespace != null) {
  187. try {
  188. new URI(targetNamespace);
  189. } catch (URISyntaxException e) {
  190. msg = MessageCatalog.getMessage("CCCB4017");
  191. text = msg.formatText(new Object[] { targetNamespace } );
  192. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  193. throw new IllegalArgumentException(text);
  194. }
  195. }
  196. /* Character encoding for DISPLAY usage fields */
  197. String displayEncoding = spec.getDisplayCharEncoding();
  198. if (displayEncoding == null) {
  199. msg = MessageCatalog.getMessage("CCCB4020");
  200. text = msg.toString();
  201. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  202. throw new IllegalArgumentException(text);
  203. }
  204. /* Character encoding for DISPLAY1 usage fields */
  205. String display1Encoding = spec.getDisplay1CharEncoding();
  206. if (display1Encoding == null) {
  207. msg = MessageCatalog.getMessage("CCCB4021");
  208. text = msg.toString();
  209. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  210. throw new IllegalArgumentException(text);
  211. }
  212. mCopybookFile = copybookFile;
  213. mCopybookCharEncoding = copybookEncoding;
  214. mXsdFile = new File(xsdLocation);
  215. mTargetNamespace = targetNamespace;
  216. mIgnoreExtraContent = spec.getIgnoreContentBeyondCol72();
  217. mCheckReservedWord = spec.getCheckNamesForReservedWords();
  218. mDisplayCharEncoding = displayEncoding;
  219. mDisplay1CharEncoding = display1Encoding;
  220. }
  221. /**
  222. * Build the XSD document. A partial document may be built should this
  223. * method fail to successfully complete.
  224. *
  225. * @param xsdDocument XSD document
  226. *
  227. * @throws CocoXsdBuilderException if any error occurs that prevents the
  228. * successful building of the XSD
  229. *
  230. * @throws java.lang.IllegalStateException if the OTD cannot be built due
  231. * to insufficient information (e.g., context not yet given)
  232. */
  233. public void buildXsd()
  234. throws CocoXsdBuilderException, IllegalStateException {
  235. if (mSpec == null) {
  236. Message msg = MessageCatalog.getMessage("CCCB4018");
  237. String text = msg.toString();
  238. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  239. throw new IllegalStateException(text);
  240. }
  241. try {
  242. /* Build intermediate model of COCOCO data */
  243. CocoLexer lexer =
  244. new CocoLexer(mCopybookFile, mCopybookCharEncoding);
  245. lexer.setDisable72ColumnLimit(!mIgnoreExtraContent);
  246. CocoParser parser = new CocoParser(lexer);
  247. parser.disableItemNameReservedWordChecking(!mCheckReservedWord);
  248. CocoDataModel model = null;
  249. model = parser.parse();
  250. /* Output parser trace info if wanted */
  251. if (mShowTrace && mXsdFile != null) {
  252. File tFile =
  253. File.createTempFile("CocoXsdBuilder", "debug", mXsdFile);
  254. PrintStream outStream =
  255. new PrintStream(new FileOutputStream(tFile));
  256. model.toStream(outStream);
  257. outStream.close();
  258. }
  259. SchemaDocument schemaDoc = SchemaDocument.Factory.newInstance();
  260. Schema schema = schemaDoc.addNewSchema();
  261. if (mTargetNamespace != null && mTargetNamespace.length() > 0) {
  262. schema.setTargetNamespace(mTargetNamespace);
  263. }
  264. createXsd(model, schema);
  265. schema.setElementFormDefault(Enum.forString("qualified"));
  266. XmlOptions options = new XmlOptions();
  267. options.setSaveAggressiveNamespaces();
  268. Map<String, String> prefixes = new HashMap<String, String>();
  269. prefixes.put("urn:com.sun:encoder", "enc");
  270. prefixes.put("urn:com.sun:encoder-coco-1.0", "coco");
  271. options.setSaveSuggestedPrefixes(prefixes);
  272. options.setSavePrettyPrint();
  273. options.setSavePrettyPrintIndent(4);
  274. options.setSavePrettyPrintOffset(0);
  275. options.setCharacterEncoding("UTF-8");
  276. schemaDoc.save(mXsdFile, options);
  277. } catch (Exception e) {
  278. throw new CocoXsdBuilderException(e.getLocalizedMessage(), e);
  279. }
  280. }
  281. /**
  282. * Populate OTD container with tree built from data model.
  283. *
  284. * @param model COBOL Copybook data model
  285. * @param schema the XML schema
  286. *
  287. * @throws CocoXsdBuilderException if any error occurs that prevents
  288. * the successful building of the tree
  289. */
  290. private void createXsd(CocoDataModel model, Schema schema)
  291. throws CocoXsdBuilderException {
  292. populateEncodingMark(schema);
  293. growXsd(model.getRoot(), new SchemaNode(schema, null, null, null));
  294. }
  295. /**
  296. * Populate encoding mark with builder parameters
  297. *
  298. * @param schema XML Schema to insert encoding mark to
  299. */
  300. private void populateEncodingMark(Schema schema) {
  301. CocoEncodingMark encodingMark = CocoEncodingMark.Factory.newInstance();
  302. Encoding encoding = encodingMark.addNewEncoding();
  303. encoding.setName("COBOL Copybook Encoder");
  304. encoding.setNamespace("urn:com.sun:encoder-coco-1.0");
  305. encoding.setStyle(CocoEncoderProvider.STYLE_ID);
  306. encodingMark.setCocoXsdBuilderVendor("SUNW");
  307. encodingMark.setCocoXsdBuilderVersion(BUILDER_VERSION);
  308. encodingMark.setCopybookCharEncoding(mCopybookCharEncoding);
  309. String inputFilename = null;
  310. try {
  311. inputFilename = mCopybookFile.getCanonicalPath();
  312. } catch (IOException ie) {
  313. inputFilename = mCopybookFile.getAbsolutePath();
  314. }
  315. encodingMark.setCopybookLocation(inputFilename);
  316. encodingMark.setIgnoreContentBeyondCol72(mIgnoreExtraContent);
  317. encodingMark.setCheckNamesForReservedWords(mCheckReservedWord);
  318. if (mXsdFile != null) {
  319. String outputFileName = null;
  320. try {
  321. outputFileName = mXsdFile.getCanonicalPath();
  322. } catch (IOException ie2) {
  323. outputFileName = mXsdFile.getAbsolutePath();
  324. }
  325. encodingMark.setXsdLocation(outputFileName);
  326. }
  327. Appinfo appInfo = schema.addNewAnnotation().addNewAppinfo();
  328. appInfo.set(encodingMark);
  329. appInfo.setSource("urn:com.sun:encoder");
  330. }
  331. /**
  332. * Populate the element with data model information.
  333. *
  334. * @param entry List of model elements to process; elements are
  335. * processed FIFO-like, that is from the head on down; list
  336. * should be "shallow" and contain sibling entries of the
  337. * immediate model tree level in regard
  338. *
  339. * @param base the schema node to grow
  340. * @throws CocoXsdBuilderException
  341. */
  342. private void growXsd(CocoDescriptionEntry entry, SchemaNode base)
  343. throws CocoXsdBuilderException {
  344. SchemaNode newNode = growNode(entry, base);
  345. if (!entry.isElementary()) {
  346. for (int i = 0; i < entry.countChildren(); i++) {
  347. growXsd(entry.getChild(i), newNode);
  348. }
  349. }
  350. plantRedefines(entry, newNode, base);
  351. plantOccursDependsOn(entry, newNode);
  352. }
  353. /**
  354. * Populate the tree with a model entry's redefinitions.
  355. *
  356. * @param entry Model entry in consideration
  357. *
  358. * @param entryElem element of the redefined object (entry)
  359. *
  360. * @param base the schema or element on which to plant the redefinitions
  361. * @throws CocoXsdBuilderException
  362. * @throws IndexOutOfBoundsException
  363. */
  364. private void plantRedefines(CocoDescriptionEntry entry,
  365. SchemaNode entryElement, SchemaNode base)
  366. throws IndexOutOfBoundsException, CocoXsdBuilderException {
  367. for (int i = 0; i < entry.countRedefinitions(); i++) {
  368. CocoDescriptionEntry redef = entry.getRedefinition(i);
  369. SchemaNode node = growNode(redef, base);
  370. setRedefine(node, entryElement.getElement());
  371. /*
  372. * plant redefine's children
  373. */
  374. for (int c = 0; c < redef.countChildren(); c++) {
  375. growXsd(redef.getChild(c), node);
  376. }
  377. }
  378. }
  379. private void setRedefine(SchemaNode redefineSubject,
  380. Element redefinedObject) {
  381. redefineSubject.getEncoding().setRedefine(redefinedObject.getName());
  382. redefineSubject.getElement().getAnnotation().getAppinfoArray(0).set(
  383. redefineSubject.getEncoding());
  384. XmlCursor cursor = redefinedObject.newCursor();
  385. cursor.setAttributeText(new QName("minOccurs"), "0");
  386. cursor.dispose();
  387. cursor = redefineSubject.getElement().newCursor();
  388. cursor.setAttributeText(new QName("minOccurs"), "0");
  389. cursor.dispose();
  390. }
  391. private void setOccursDependOn(SchemaNode entryNode,
  392. SchemaNode nodeBeingDepended) {
  393. CocoEncoding encoding = entryNode.getEncoding();
  394. OccursDependOn occurs = encoding.addNewOccursDependOn();
  395. QName qName =
  396. new QName(nodeBeingDepended.getSchema().getTargetNamespace(),
  397. nodeBeingDepended.getTopElement().getName());
  398. occurs.setTopElement(qName);
  399. occurs.setPath(nodeBeingDepended.getPath());
  400. entryNode.getElement().getAnnotation().getAppinfoArray(0).set(encoding);
  401. }
  402. /**
  403. * Store the reference information of an entry's depends-on entry into
  404. * the entry element's annotation
  405. *
  406. * @param entry depends-on's <em>subject</em> entry description
  407. *
  408. * @param entryElement <code>entry's</code> element
  409. */
  410. private void plantOccursDependsOn(final CocoDescriptionEntry entry,
  411. final SchemaNode entryElement) throws CocoXsdBuilderException {
  412. final CocoDescriptionEntry depends = entry.getOccursOn();
  413. SchemaNode refNode;
  414. if (null != depends) {
  415. refNode = mEntriesToNodes.get(depends);
  416. if (null != refNode) {
  417. setOccursDependOn(entryElement, refNode);
  418. } else {
  419. Message msg = MessageCatalog.getMessage("CCCB4102");
  420. String text = msg.formatText(new Object[]{
  421. depends.getName(),
  422. entryElement.getElement().getName()
  423. });
  424. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  425. throw new CocoXsdBuilderException(text);
  426. }
  427. }
  428. }
  429. Group getSequenceGroup(Element elem) {
  430. LocalComplexType cType;
  431. if (elem.isSetComplexType()) {
  432. cType = elem.getComplexType();
  433. } else {
  434. cType = elem.addNewComplexType();
  435. }
  436. if (cType.isSetSequence()) {
  437. return cType.getSequence();
  438. } else {
  439. return cType.addNewSequence();
  440. }
  441. }
  442. /**
  443. * Grow a node for a data model entry.
  444. *
  445. * @param entry The data model entry to process
  446. *
  447. * @param base The schema node to grow leaf
  448. *
  449. * @return the newly created element
  450. */
  451. private SchemaNode growNode(CocoDescriptionEntry entry, SchemaNode base) {
  452. String name = entry.getName();
  453. Element elem = null;
  454. boolean isTop = (base.getElement() == null);
  455. if (isTop) {
  456. elem = base.getSchema().addNewElement();
  457. base.setTopElement(elem);
  458. } else {
  459. elem = getSequenceGroup(base.getElement()).addNewElement();
  460. }
  461. elem.setName(name);
  462. if (!isTop) {
  463. XmlCursor cursor = elem.newCursor();
  464. cursor.toLastAttribute();
  465. cursor.toNextToken();
  466. cursor.insertAttributeWithValue(new QName("minOccurs"),
  467. String.valueOf(entry.getMinimumOccurs()));
  468. cursor.insertAttributeWithValue(new QName("maxOccurs"),
  469. String.valueOf(entry.getMaximumOccurs()));
  470. cursor.dispose();
  471. }
  472. CocoEncoding encoding = defineElement(entry, elem);
  473. if (isTop) {
  474. encoding.setTop(true);
  475. if (mSpec.getPreDecodeCharCoding() != null) {
  476. encoding.setPreDecodeCharCoding(
  477. mSpec.getPreDecodeCharCoding());
  478. }
  479. if (mSpec.getPostEncodeCharCoding() != null) {
  480. encoding.setPostEncodeCharCoding(
  481. mSpec.getPostEncodeCharCoding());
  482. }
  483. encoding.setDisplayCharEncoding(mDisplayCharEncoding);
  484. encoding.setDisplay1CharEncoding(mDisplay1CharEncoding);
  485. elem.getAnnotation().getAppinfoArray(0).set(encoding);
  486. }
  487. SchemaNode node;
  488. if (base.getElement() == null) {
  489. node = new SchemaNode(base.getSchema(), elem, "", encoding);
  490. } else {
  491. node =
  492. new SchemaNode(base.getSchema(), elem,
  493. base.getPath().length() == 0 ? name
  494. : base.getPath() + "/" + name,
  495. encoding);
  496. }
  497. node.setTopElement(base.getTopElement());
  498. mEntriesToNodes.put(entry, node);
  499. return node;
  500. }
  501. /**
  502. * Encode data model entry into serial overlay.
  503. *
  504. * @param entry The data model entry in consideration
  505. *
  506. * @param elem The element representation of the entry
  507. */
  508. private CocoEncoding defineElement(CocoDescriptionEntry entry,
  509. Element elem) {
  510. return entry.toElement(elem);
  511. }
  512. private class SchemaNode {
  513. private final Schema mSchema;
  514. private final Element mElem;
  515. private final String mPath;
  516. private final CocoEncoding mEncoding;
  517. private Element mTopElement;
  518. public SchemaNode(Schema schema, Element elem, String path,
  519. CocoEncoding encoding) {
  520. mSchema = schema;
  521. mElem = elem;
  522. mPath = path;
  523. mEncoding = encoding;
  524. }
  525. public Schema getSchema() {
  526. return mSchema;
  527. }
  528. public Element getElement() {
  529. return mElem;
  530. }
  531. public String getPath() {
  532. return mPath;
  533. }
  534. public CocoEncoding getEncoding() {
  535. return mEncoding;
  536. }
  537. public void setTopElement(Element topElem) {
  538. mTopElement = topElem;
  539. }
  540. public Element getTopElement() {
  541. return mTopElement;
  542. }
  543. }
  544. }