PageRenderTime 29ms CodeModel.GetById 0ms RepoModel.GetById 1ms app.codeStats 0ms

/ojc-core/encodersl/encoder-coco/src/com/sun/encoder/coco/runtime/MarshalHandler.java

https://bitbucket.org/pymma/openesb-components
Java | 636 lines | 527 code | 45 blank | 64 comment | 106 complexity | a26799d83582146e3da8072637c80d9b 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. * @(#)MarshalHandler.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.runtime;
  30. import java.io.IOException;
  31. import java.io.OutputStream;
  32. import java.math.BigDecimal;
  33. import java.util.LinkedList;
  34. import javax.xml.namespace.QName;
  35. import org.xml.sax.Attributes;
  36. import org.xml.sax.ContentHandler;
  37. import org.xml.sax.Locator;
  38. import org.xml.sax.SAXException;
  39. import com.sun.encoder.coco.runtime.messages.ErrorManager;
  40. import com.sun.encoder.coco.runtime.messages.Message;
  41. import com.sun.encoder.coco.runtime.messages.MessageCatalog;
  42. import com.sun.encoder.runtime.provider.Misc;
  43. import java.util.logging.Level;
  44. import java.util.logging.Logger;
  45. import com.sun.encoder.runtime.provider.Misc;
  46. /**
  47. * This class implements SAX <code>ContentHandler</code> interface.
  48. * It translates SAX events into COBOL Copybook encoded data.
  49. *
  50. * @author Jun Xu
  51. * @since 6.0
  52. * @version $Revision: 1.2 $
  53. */
  54. public final class MarshalHandler implements ContentHandler {
  55. private static final ErrorManager cErrorMgr =
  56. ErrorManager.getManager("OpenESB.encoder.COBOLCopybook."
  57. + MarshalHandler.class.getName());
  58. private final RuleNode mTopRule;
  59. private final OutputStream mOutputStream;
  60. private final NoSyncStack<MarshalContext> mStack;
  61. private final StringBuilder mBuffer = new StringBuilder(1024);
  62. private final boolean[] mTrackRedefined;
  63. private final Integer[] mOccursDependOn;
  64. Logger mLog = Logger.getLogger(getClass().getName());
  65. static final String LN = System.getProperty("line.separator");
  66. private enum MatchDirection {
  67. FIRST_CHILD,
  68. CURRENT,
  69. NEXT_SIBLING
  70. }
  71. private MatchDirection mMatchDirection;
  72. private RuleNode mRuleToBeSkipped = null;
  73. private int mSkippingLevel;
  74. public MarshalHandler(RuleNode topRule, OutputStream output) {
  75. if (topRule == null) {
  76. throw new NullPointerException("no top rule.");
  77. }
  78. if (output == null) {
  79. throw new NullPointerException("no output");
  80. }
  81. mTopRule = topRule;
  82. mTrackRedefined =
  83. new boolean[mTopRule.getContext().getRedefinedNodes().length];
  84. mOccursDependOn =
  85. new Integer[mTopRule.getContext().getOccursDependOnNodes().length];
  86. mOutputStream = output;
  87. mStack = new NoSyncStack<MarshalContext>();
  88. mStack.push(new MarshalContext(RuleNode.wrapAsSuperNode(mTopRule)));
  89. mMatchDirection = MatchDirection.FIRST_CHILD;
  90. mSkippingLevel = 0;
  91. if (mLog.isLoggable(Level.FINE)) {
  92. mLog.fine(" topRule=" + mTopRule);
  93. }
  94. }
  95. public void startElement(String uri, String localName, String qName,
  96. Attributes atts)
  97. throws SAXException {
  98. if (mLog.isLoggable(Level.FINE)) {
  99. StringBuilder sb = new StringBuilder();
  100. sb.append("Enter: startElement '").append(localName).append("'");
  101. if (!localName.equals(qName)) {
  102. sb.append(", qName='").append(qName).append("'");
  103. }
  104. if (mLog.isLoggable(Level.FINER)) {
  105. if (atts.getLength() > 0) {
  106. sb.append(",").append(LN).append(" attributes={");
  107. }
  108. for (int i = 0; i < atts.getLength(); i++) {
  109. sb.append(" attribute[").append(i).append("]=[");
  110. sb.append(atts.getQName(i)).append("=");
  111. sb.append(atts.getValue(i)).append("]");
  112. }
  113. if (atts.getLength() > 0) {
  114. sb.append("}");
  115. }
  116. }
  117. sb.append(". ");
  118. if (mLog.isLoggable(Level.FINEST)) {
  119. sb.append(getContextDetails(Level.FINEST));
  120. mLog.finest(sb.toString());
  121. } else {
  122. sb.append(getContextDetails(Level.FINE));
  123. mLog.fine(sb.toString());
  124. }
  125. }
  126. if (isSkipping() && mSkippingLevel > 0) {
  127. mSkippingLevel++;
  128. return;
  129. }
  130. RuleNode matchedNode = match(uri, localName);
  131. if (matchedNode != mStack.peek().mRule) {
  132. //end of repetition or found first child
  133. mStack.push(new MarshalContext(matchedNode));
  134. mStack.peek().mRepetition = 1;
  135. } else {
  136. mStack.peek().mRepetition++;
  137. }
  138. enterProc(mStack.peek());
  139. mMatchDirection = MatchDirection.FIRST_CHILD;
  140. if (!isSkipping()) {
  141. mBuffer.setLength(0);
  142. }
  143. if (mLog.isLoggable(Level.FINE)) {
  144. StringBuilder sb = new StringBuilder("Exit: startElement '");
  145. sb.append(localName).append("'. ");
  146. if (mLog.isLoggable(Level.FINEST)) {
  147. sb.append(getContextDetails(Level.FINEST));
  148. mLog.finest(sb.toString());
  149. } else {
  150. sb.append(getContextDetails(Level.FINE));
  151. mLog.fine(sb.toString());
  152. }
  153. }
  154. }
  155. public void characters(char[] chars, int start, int length)
  156. throws SAXException {
  157. if (mLog.isLoggable(Level.FINE)) {
  158. mLog.fine("Receive: character data="
  159. + Misc.printable(new String(chars, start, length)) + ".");
  160. }
  161. if (!isSkipping()) {
  162. mBuffer.append(chars, start, length);
  163. }
  164. }
  165. public void endElement(String uri, String localName, String qName)
  166. throws SAXException {
  167. if (mLog.isLoggable(Level.FINE)) {
  168. StringBuilder sb = new StringBuilder("Enter: endElement '");
  169. sb.append(localName).append("'");
  170. if (!localName.equals(qName)) {
  171. sb.append(", qName='").append(qName).append("'");
  172. }
  173. sb.append(". ");
  174. if (mLog.isLoggable(Level.FINEST)) {
  175. sb.append(getContextDetails(Level.FINEST));
  176. mLog.finest(sb.toString());
  177. } else {
  178. sb.append(getContextDetails(Level.FINE));
  179. mLog.fine(sb.toString());
  180. }
  181. }
  182. if (isSkipping() && mSkippingLevel > 0) {
  183. mSkippingLevel--;
  184. if (mSkippingLevel == 0) {
  185. mMatchDirection = mStack.peek().mRule.getMaxOccurs() > 1 ?
  186. MatchDirection.CURRENT : MatchDirection.NEXT_SIBLING;
  187. }
  188. return;
  189. }
  190. if (mMatchDirection != MatchDirection.FIRST_CHILD) {
  191. exitProc(mStack.pop(), uri, localName);
  192. } else {
  193. try {
  194. flushData();
  195. } catch (IOException e) {
  196. // re-throw
  197. throw new SAXException(e);
  198. }
  199. }
  200. RuleNode rule = mStack.peek().mRule;
  201. mMatchDirection = rule.getMaxOccurs() > 1 ?
  202. MatchDirection.CURRENT : MatchDirection.NEXT_SIBLING;
  203. int idx = rule.getOccursDependOnIndex();
  204. if (idx >= 0) {
  205. mOccursDependOn[idx] = new Integer(mBuffer.toString());
  206. }
  207. RuleNode[] children = rule.getChildren();
  208. if (children != null) {
  209. for (int i = 0; i < children.length; i++) {
  210. if (children[i].getRedefineIndex() >= 0
  211. && !mTrackRedefined[children[i].getRedefineIndex()]) {
  212. throw new SAXException("Value is missing for "
  213. + "redefined entry: "
  214. + rule.getContext().getRedefinedNodes()
  215. [children[i].getRedefineIndex()].getQName());
  216. }
  217. }
  218. }
  219. if (mLog.isLoggable(Level.FINE)) {
  220. StringBuilder sb = new StringBuilder("Exit: endElement '");
  221. sb.append(localName).append("'. ");
  222. if (mLog.isLoggable(Level.FINEST)) {
  223. sb.append(getContextDetails(Level.FINEST));
  224. mLog.finest(sb.toString());
  225. } else {
  226. sb.append(getContextDetails(Level.FINE));
  227. mLog.fine(sb.toString());
  228. }
  229. }
  230. }
  231. public void startDocument() throws SAXException {
  232. //no-op
  233. }
  234. public void processingInstruction(String target, String data)
  235. throws SAXException {
  236. //no-op
  237. }
  238. public void setDocumentLocator(Locator locator) {
  239. //no-op
  240. }
  241. public void skippedEntity(String name) throws SAXException {
  242. //no-op
  243. }
  244. public void ignorableWhitespace(char[] ch, int start, int length)
  245. throws SAXException {
  246. //no-op
  247. }
  248. public void startPrefixMapping(String prefix, String uri)
  249. throws SAXException {
  250. //no-op
  251. }
  252. public void endPrefixMapping(String prefix) throws SAXException {
  253. //no-op
  254. }
  255. public void endDocument() throws SAXException {
  256. //no-op
  257. }
  258. private RuleNode match(String uri, String localName)
  259. throws SAXException {
  260. if (mLog.isLoggable(Level.FINER)) {
  261. mLog.finer("Match node: '" + localName + "', uri='" + uri + "'.");
  262. }
  263. RuleNode currentRule = mStack.peek().mRule;
  264. int index;
  265. switch (mMatchDirection) {
  266. case FIRST_CHILD:
  267. index = 0;
  268. break;
  269. case CURRENT:
  270. if (currentRule.getQName().getLocalPart().equals(localName)) {
  271. if (mLog.isLoggable(Level.FINER)) {
  272. mLog.finer("Matched node=" + currentRule);
  273. }
  274. return currentRule;
  275. }
  276. default: //Must be NEXT_SIBLING
  277. exitProc(mStack.pop(), uri, localName);
  278. index = currentRule.getIndex() + 1;
  279. currentRule = mStack.peek().mRule;
  280. break;
  281. }
  282. RuleNode[] children = currentRule.getChildren();
  283. if (children == null) {
  284. throw new SAXException(
  285. "No matched rule for tag: '" + localName + "'");
  286. }
  287. while (index < children.length) {
  288. if (children[index].getQName().getLocalPart().equals(localName)) {
  289. if (mLog.isLoggable(Level.FINER)) {
  290. mLog.finer("Matched node=" + children[index]);
  291. }
  292. return children[index];
  293. } else if (children[index].getMinOccurs() > 0) {
  294. throw new SAXException("Expecting: " + children[index].getQName()
  295. + ", found: " + new QName(uri, localName));
  296. }
  297. index++;
  298. }
  299. throw new SAXException(
  300. "No matched rule for tag: '" + localName + "'");
  301. }
  302. /**
  303. * Process when pushed into the stack.
  304. *
  305. * @param context
  306. */
  307. private void enterProc(MarshalContext context) {
  308. RuleNode redefinedNode = context.mRule.getRedefinedNode();
  309. if (redefinedNode != null) {
  310. if (mTrackRedefined[redefinedNode.getRedefineIndex()]) {
  311. mRuleToBeSkipped = context.mRule;
  312. mSkippingLevel = 1;
  313. }
  314. }
  315. if (!isSkipping()) {
  316. RuleNode[] children = context.mRule.getChildren();
  317. if (children != null) {
  318. for (int i = 0; i < children.length; i++) {
  319. if (children[i].getRedefineIndex() >= 0) {
  320. mTrackRedefined[children[i].getRedefineIndex()] = false;
  321. }
  322. }
  323. }
  324. }
  325. }
  326. private boolean isSkipping() {
  327. return mRuleToBeSkipped != null;
  328. }
  329. /**
  330. * Process when popped from the stack.
  331. *
  332. * @param context
  333. * @param uri namespace URI of the tag currently seen
  334. * @param localName local name of the tag currently seen
  335. * @throws SAXException
  336. */
  337. private void exitProc(MarshalContext context, String uri, String localName)
  338. throws SAXException {
  339. if (context.mRule == mRuleToBeSkipped) {
  340. mRuleToBeSkipped = null;
  341. mSkippingLevel = 0;
  342. return;
  343. }
  344. if (context.mRule.getRedefineIndex() >= 0) {
  345. mTrackRedefined[context.mRule.getRedefineIndex()] = true;
  346. }
  347. RuleNode redefined = context.mRule.getRedefinedNode();
  348. if (redefined != null) {
  349. mTrackRedefined[redefined.getRedefineIndex()] = true;
  350. }
  351. RuleNode dependOn = context.mRule.getOccursDependOn();
  352. if (dependOn != null) {
  353. Integer occurs = mOccursDependOn[dependOn.getOccursDependOnIndex()];
  354. if (occurs == null) {
  355. throw new SAXException(
  356. "Occurs Depending On value is missing for "
  357. + context.mRule.getQName());
  358. }
  359. if (context.mRepetition < occurs.intValue()) {
  360. throw new SAXException(
  361. context.mRule.getQName()
  362. + " should repeat " + occurs
  363. + " time(s) but now it only repeated "
  364. + context.mRepetition + " time(s)");
  365. } else if (context.mRepetition < occurs.intValue()) {
  366. throw new SAXException(
  367. context.mRule.getQName()
  368. + " can only repeat " + occurs + " time(s) but now it"
  369. + " repeated " + context.mRepetition + " time(s)");
  370. }
  371. } else {
  372. if (context.mRepetition < context.mRule.getMinOccurs()) {
  373. throw new SAXException("Expecting: " + context.mRule.getQName()
  374. + ", found: " + new QName(uri, localName));
  375. }
  376. }
  377. }
  378. private void flushData() throws SAXException, IOException {
  379. RuleNode rule = mStack.peek().mRule;
  380. if (rule.getChildren() != null && rule.getChildren().length > 0) {
  381. // non-leaf rule node, then do nothing
  382. return;
  383. }
  384. // must be a leaf rule
  385. String data = mBuffer.toString();
  386. if (mLog.isLoggable(Level.FINEST)) {
  387. mLog.fine("Save buffer to output, data=" + Misc.printable(data));
  388. } else {
  389. mLog.fine("Save buffer to output.");
  390. }
  391. switch (rule.getCharacteristics().getUsage()) {
  392. case CobolCharacteristics.USAGE_COMP1:
  393. CobolDataConverter.encodeToFloat(
  394. mOutputStream,
  395. Float.parseFloat(data));
  396. break;
  397. case CobolCharacteristics.USAGE_COMP2:
  398. CobolDataConverter.encodeToDouble(
  399. mOutputStream,
  400. Double.parseDouble(data));
  401. break;
  402. case CobolCharacteristics.USAGE_BINARY:
  403. case CobolCharacteristics.USAGE_COMP:
  404. case CobolCharacteristics.USAGE_COMP4:
  405. CobolDataConverter.encodeToBinary(
  406. mOutputStream,
  407. new BigDecimal(data),
  408. rule.getPicture(),
  409. rule.getCharacteristics());
  410. break;
  411. case CobolCharacteristics.USAGE_PACKED:
  412. case CobolCharacteristics.USAGE_COMP3:
  413. CobolDataConverter.encodeToPacked(
  414. mOutputStream,
  415. new BigDecimal(data),
  416. rule.getPicture(),
  417. rule.getCharacteristics());
  418. break;
  419. case CobolCharacteristics.USAGE_COMP5:
  420. CobolDataConverter.encodeToNativeBinary(
  421. mOutputStream,
  422. new BigDecimal(data),
  423. rule.getPicture(),
  424. rule.getCharacteristics());
  425. break;
  426. case CobolCharacteristics.USAGE_INDEX:
  427. CobolDataConverter.encodeToIndex(
  428. mOutputStream,
  429. Integer.parseInt(data),
  430. rule.getCharacteristics());
  431. break;
  432. case CobolCharacteristics.USAGE_DISPLAY:
  433. switch (rule.getCharacteristics().getPicCategory()) {
  434. case CobolCharacteristics.PIC_EXFLOAT:
  435. CobolDataConverter.encodeToExternalFloat(
  436. mOutputStream,
  437. new BigDecimal(data),
  438. rule.getPicture(),
  439. rule.getCharacteristics(),
  440. rule.getCharEncoding());
  441. break;
  442. case CobolCharacteristics.PIC_NUM:
  443. CobolDataConverter.encodeToZoned(
  444. mOutputStream,
  445. new BigDecimal(data),
  446. rule.getPicture(),
  447. rule.getCharacteristics(),
  448. rule.getCharEncoding());
  449. break;
  450. case CobolCharacteristics.PIC_ALPHA:
  451. case CobolCharacteristics.PIC_ALPHANUM:
  452. case CobolCharacteristics.PIC_ALPHANUME:
  453. case CobolCharacteristics.PIC_NUME:
  454. CobolDataConverter.encodeToDisplay(
  455. mOutputStream,
  456. data,
  457. rule.getCharacteristics(),
  458. rule.getCharEncoding());
  459. break;
  460. case CobolCharacteristics.PIC_DBCS:
  461. //Don't know if this possible, but just in case
  462. CobolDataConverter.encodeToDbcs(
  463. mOutputStream,
  464. data.getBytes(
  465. rule.getCharEncoding()),
  466. rule.getCharacteristics().getSize());
  467. break;
  468. default:
  469. Message msg =
  470. MessageCatalog.getMessage("CCCB4113");
  471. String err =
  472. msg.formatText(new Object[]{rule.getQName(),
  473. rule.getCharacteristics().getUsage()});
  474. cErrorMgr.log(
  475. ErrorManager.Severity.ERROR, null, err);
  476. throw new SAXException(err);
  477. } // end of switch (PicCategory)
  478. break;
  479. case CobolCharacteristics.USAGE_DISPLAY1:
  480. CobolDataConverter.encodeToDbcs(
  481. mOutputStream,
  482. data.getBytes(
  483. rule.getCharEncoding()),
  484. rule.getCharacteristics().getSize());
  485. break;
  486. default:
  487. Message msg = MessageCatalog.getMessage("CCCB4112");
  488. String err =
  489. msg.formatText(new Object[]{rule.getQName(),
  490. rule.getCharacteristics().getUsage()});
  491. cErrorMgr.log(ErrorManager.Severity.ERROR, null, err);
  492. throw new SAXException(err);
  493. } // end of switch (Usage)
  494. }
  495. private static final class MarshalContext {
  496. public final RuleNode mRule;
  497. public int mRepetition;
  498. public MarshalContext(RuleNode rule) {
  499. mRule = rule;
  500. }
  501. @Override
  502. public String toString() {
  503. StringBuffer buf = new StringBuffer("MarshalContext@")
  504. .append(Integer.toHexString(hashCode()));
  505. buf.append(" ruleNode=").append(mRule);
  506. buf.append(" repetition=").append(mRepetition);
  507. return buf.toString();
  508. }
  509. // for debug
  510. String id() {
  511. return mRule.getQName().getLocalPart();
  512. }
  513. }
  514. private class NoSyncStack<E> extends LinkedList<E> {
  515. private static final long serialVersionUID = 1L;
  516. public void push(E o) {
  517. add(o);
  518. }
  519. public E pop() {
  520. if (!isEmpty()) {
  521. return removeLast();
  522. }
  523. throw new RuntimeException("Stack underflow.");
  524. }
  525. @Override
  526. public E peek() {
  527. if (!isEmpty()) {
  528. return getLast();
  529. }
  530. throw new RuntimeException("Stack underflow.");
  531. }
  532. // for debug
  533. String id() {
  534. StringBuilder sb = new StringBuilder();
  535. for (int i = 0; i < size(); i++) {
  536. sb.append(((MarshalContext) get(i)).id());
  537. if (i < size() - 1) {
  538. sb.append(", ");
  539. }
  540. }
  541. return sb.toString();
  542. }
  543. }
  544. private String getContextDetails(Level logLevel) {
  545. StringBuilder sb = new StringBuilder();
  546. sb.append(" Details: buffer=").append(Misc.printable(mBuffer.toString()));
  547. if (mStack != null) {
  548. sb.append(" stack=");
  549. if (Level.FINEST.equals(logLevel)) {
  550. sb.append(mStack);
  551. } else {
  552. sb.append("[").append(mStack.id()).append("]");
  553. }
  554. }
  555. if (mTrackRedefined.length > 0) {
  556. sb.append(" trackRedefined=[");
  557. for (int i = 0; i < mTrackRedefined.length; i++) {
  558. sb.append(mTrackRedefined[i]);
  559. if (i < mTrackRedefined.length - 1) {
  560. sb.append(", ");
  561. }
  562. }
  563. sb.append("]");
  564. }
  565. if (mOccursDependOn.length > 0) {
  566. sb.append(" occursDependOn=[");
  567. for (int i = 0; i < mOccursDependOn.length; i++) {
  568. sb.append(mOccursDependOn[i]);
  569. if (i < mOccursDependOn.length - 1) {
  570. sb.append(", ");
  571. }
  572. }
  573. sb.append("]");
  574. }
  575. if (mMatchDirection != null) {
  576. sb.append(" matchDirection=").append(mMatchDirection);
  577. }
  578. if (mRuleToBeSkipped != null) {
  579. sb.append(" ruleToBeSkipped=");
  580. if (Level.FINEST.equals(logLevel)) {
  581. sb.append(mRuleToBeSkipped);
  582. } else {
  583. sb.append(mRuleToBeSkipped.getQName().getLocalPart());
  584. }
  585. }
  586. if (mSkippingLevel > -1) {
  587. sb.append(" skippingLevel=").append(mSkippingLevel);
  588. }
  589. return sb.toString();
  590. }
  591. }