PageRenderTime 68ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/ojc-core/encodersl/encoder-coco/src/com/sun/encoder/coco/model/CocoDataModel.java

https://bitbucket.org/pymma/openesb-components
Java | 890 lines | 596 code | 55 blank | 239 comment | 187 complexity | 86cd967e68b81979b737568c6f8e0a7f 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. * @(#)CocoDataModel.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.model;
  30. import java.io.PrintStream;
  31. import java.util.ArrayList;
  32. import java.util.Collections;
  33. import java.util.List;
  34. import java.util.Vector;
  35. import java.util.ListIterator;
  36. import java.util.HashMap;
  37. import java.util.Map;
  38. import java.util.Iterator;
  39. import java.util.regex.Matcher;
  40. import java.util.regex.Pattern;
  41. import com.sun.encoder.coco.runtime.messages.ErrorManager;
  42. import com.sun.encoder.coco.runtime.messages.Message;
  43. import com.sun.encoder.coco.runtime.messages.MessageCatalog;
  44. /**
  45. * The data model for information parsed from Cobol Copybook input.
  46. *
  47. * @author Noel Ang
  48. *
  49. * @version $Revision: 1.2 $
  50. *
  51. * @see com.sun.encoder.coco.model.CocoParser
  52. */
  53. public class CocoDataModel {
  54. private CocoDescriptionEntry mRootEntry;
  55. private List<CocoDescriptionEntry> mEntries;
  56. private boolean mImplied01;
  57. private long mFillerCount;
  58. private long mBlankCount;
  59. // FQN collision table
  60. private Map<String, Object> mNames;
  61. // base name collision table
  62. private Map<String, Vector> mBaseNames;
  63. private Map<String, Integer> mHlqs;
  64. private List mUnresolvedOccurs;
  65. private final ErrorManager mErrorMgr =
  66. ErrorManager.getManager("OpenESB.encoder.CobolCopybook."
  67. + getClass().getName());
  68. /**
  69. * Default constructor. Creates an empty data model.
  70. */
  71. public CocoDataModel() {
  72. mEntries =
  73. Collections.synchronizedList(
  74. new ArrayList<CocoDescriptionEntry>());
  75. mRootEntry = new CocoDescriptionEntry("FILLER", 1);
  76. mRootEntry.setFQN(mRootEntry.getName());
  77. mImplied01 = true;
  78. mFillerCount = 0;
  79. mBlankCount = 0;
  80. mNames = new HashMap<String, Object>();
  81. mBaseNames = new HashMap<String, Vector>();
  82. mHlqs = new HashMap<String, Integer>();
  83. mEntries.add(mRootEntry);
  84. }
  85. /**
  86. * Add a description entry to the model. The entry is validated prior to
  87. * being added, for such things such as names, level numbers,
  88. * (TODO) mutually exclusive clauses, etc.
  89. *
  90. * @param entry The description entry to add
  91. *
  92. * @throws java.lang.IllegalArgumentException if the entry cannot be
  93. * validated for this model
  94. */
  95. public void addEntry(CocoDescriptionEntry entry)
  96. throws IllegalArgumentException {
  97. validateName(entry);
  98. /* ignore special levels */
  99. int level = entry.getLevel();
  100. if (level < 1 || level == 66 || level == 77 || level == 88) {
  101. return;
  102. }
  103. mEntries.add(entry);
  104. /*
  105. * redefined entries already keep references to redefinitions, so
  106. * ignore starting redefs
  107. */
  108. if (entry.isRedefinition()) {
  109. // need to register base name and FQN here
  110. // also - redef should not conflict with any same level entry
  111. // within the same parent entry;
  112. CocoDescriptionEntry redefTarget = entry.getRedefinedTarget();
  113. if ( redefTarget != null ) {
  114. this.registerBaseName(entry);
  115. CocoDescriptionEntry parent = redefTarget.getParent();
  116. String fqn = null;
  117. if ( parent != null )
  118. fqn = parent.getFQN() + ":" + entry.getName();
  119. else
  120. fqn = entry.getName();
  121. entry.setFQN(fqn);
  122. if ( this.mNames.containsKey(fqn) ) {
  123. String parentName = "";
  124. if ( parent != null )
  125. parentName = parent.getInfo();
  126. Message msg = MessageCatalog.getMessage("CCCB4228");
  127. String text = msg.formatText(new Object[] {
  128. entry.getInfo() + "(REDEFINE)",
  129. parentName
  130. });
  131. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  132. throw new IllegalArgumentException(text);
  133. }
  134. this.registerFQN(entry);
  135. }
  136. else {
  137. //
  138. }
  139. return;
  140. }
  141. if (level == 1) {
  142. if (mImplied01) {
  143. mImplied01 = false;
  144. mEntries.remove(mRootEntry);
  145. mRootEntry = entry;
  146. entry.setFQN(entry.getName());
  147. mNames.put(entry.getFQN(), entry);
  148. registerBaseName(entry);
  149. } else {
  150. // multi 01 not supported
  151. Message msg = MessageCatalog.getMessage("CCCB4104");
  152. String text = msg.toString();
  153. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  154. throw new IllegalArgumentException(text);
  155. }
  156. }
  157. else {
  158. /* once I have begun to add non-level 1 entries, then the
  159. * current level 1 entry, whether it is an implied 01 or an
  160. * data input-inserted 01 needs to be locked; no 01 replacement
  161. * is hereafter possible.
  162. */
  163. mImplied01 = false;
  164. // building the tree - closest scope to the top
  165. int entryIx = mEntries.size() - 1;
  166. do {
  167. CocoDescriptionEntry last =
  168. (CocoDescriptionEntry) mEntries.get(entryIx);
  169. int lastLevel = last.getLevel();
  170. if (lastLevel < level) {
  171. // derive FQN here and check conflict in the current scope
  172. last.addChild(entry);
  173. // before we add child - check if the parent has a PIC
  174. // or its usage is an explicit COMP-1 or COMP-2;
  175. // clause - a group item should not has PIC clause
  176. String pic = last.getPicture();
  177. if ( pic == null || pic.trim().length() == 0 ) {
  178. // this is OK since the parent entry should not
  179. // have a PIC - ONLY elementary item should
  180. }
  181. else {
  182. Message msg = MessageCatalog.getMessage("CCCB4229");
  183. String text = msg.formatText(new Object[] {
  184. entry.getInfo(),
  185. last.getInfo()
  186. });
  187. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  188. throw new IllegalArgumentException(text);
  189. }
  190. String fqn = obtainFQN(entry);
  191. entry.setFQN(fqn);
  192. if ( this.mNames.containsKey(fqn) ) {
  193. String parentName = "";
  194. CocoDescriptionEntry parent = entry.getParent();
  195. if ( parent != null )
  196. parentName = parent.getInfo();
  197. Message msg = MessageCatalog.getMessage("CCCB4228");
  198. String text = msg.formatText(new Object[] {
  199. entry.getInfo(),
  200. parentName
  201. });
  202. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  203. throw new IllegalArgumentException(text);
  204. }
  205. registerFQN(entry);
  206. registerBaseName(entry);
  207. break;
  208. } else {
  209. entryIx--;
  210. }
  211. } while (entryIx >= 0);
  212. }
  213. }
  214. /**
  215. * given a entry in the entry hierarchy, derive its FQN - i.e.
  216. * entry's own name qualified by its parents name
  217. * @param entry_added
  218. * @return
  219. */
  220. private String obtainFQN(CocoDescriptionEntry entry_added) {
  221. StringBuffer fqn = new StringBuffer(entry_added.getName());
  222. CocoDescriptionEntry parent = entry_added.getParent();
  223. if ( parent != null )
  224. fqn.insert(0, ":").insert(0, parent.getFQN());
  225. return fqn.toString();
  226. }
  227. /**
  228. * do all the possible copy book validation here
  229. * for now, we check if a data item does not have any child
  230. * and does not have a PIC clause either
  231. */
  232. public void validate() {
  233. if ( mEntries != null ) {
  234. int cnt = mEntries.size();
  235. CocoDescriptionEntry entry = null;
  236. for (int i = 0; i < cnt; i++ ) {
  237. entry = (CocoDescriptionEntry)mEntries.get(i);
  238. if ( entry.countChildren() == 0 ) {
  239. // for leaf item further check if it
  240. // has pic clause - if no - invalid item but
  241. // note, COMP-1, COMP-2 does not have PIC but is elementary;
  242. // exclude redefine item for this checking
  243. if ( !entry.isRedefinition() ) {
  244. String pic = entry.getPicture();
  245. int usage = getRealUsage(entry);
  246. // per 93394 further check PIC and USAGE compatibleness
  247. if ( usage != CocoDescriptionEntry.UsageType.COMP1
  248. && usage != CocoDescriptionEntry.UsageType.COMP2
  249. && (pic == null || pic.trim().length() == 0) ) {
  250. Message msg = MessageCatalog.getMessage("CCCB4230");
  251. String text = msg.formatText(new Object[] {
  252. entry.getInfo()
  253. });
  254. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  255. throw new IllegalArgumentException(text);
  256. }
  257. // COMP1 or COMP2 or PIC
  258. // check usage and pic compatibleness - rules (may be
  259. // not complete but can block away common seen semantic
  260. // bad data description entries)
  261. // for COMP1 & 2 - this is a non issue
  262. // validate only other comp and numeirc entry
  263. if ( usage == CocoDescriptionEntry.UsageType.COMP
  264. || usage ==
  265. CocoDescriptionEntry.UsageType.BINARY
  266. || usage ==
  267. CocoDescriptionEntry.UsageType.PACDEC
  268. || usage ==
  269. CocoDescriptionEntry.UsageType.COMP3
  270. || usage ==
  271. CocoDescriptionEntry.UsageType.COMP5 ) {
  272. // should contain only '9', 'S', 's', 'V', 'v',
  273. // 'P', 'p' the following regex might be more
  274. // relaxed than a valid COBOL numeric data entry
  275. // picture - but blocking away those
  276. // that does not match this regex is enough
  277. String patternStr =
  278. "^[sS]*9*[\\([0-9]+\\)]*[vV]*9*[\\([0-9]+\\)]*[pP]*$";
  279. Pattern pattern =
  280. Pattern.compile(patternStr);
  281. //Pattern pattern = Pattern.compile("^[9SsVvPp]*$");
  282. Matcher match = pattern.matcher(pic);
  283. if ( !match.matches() ) {
  284. Message msg =
  285. MessageCatalog.getMessage("CCCB4231");
  286. String text = msg.formatText(new Object[] {
  287. entry.getInfo(),
  288. pic,
  289. entry.getUsageName(usage)
  290. });
  291. mErrorMgr.log(
  292. ErrorManager.Severity.ERROR,
  293. null, text);
  294. throw new IllegalArgumentException(text);
  295. }
  296. }
  297. }
  298. }
  299. }
  300. }
  301. }
  302. /**
  303. * helper - retrieve the real usage of the given entry
  304. * real usage is the explicit usage of its closest ancester or usage
  305. * of itself if all the ancesters have implicit usage;
  306. *
  307. * @param entry
  308. * @return
  309. */
  310. private int getRealUsage(CocoDescriptionEntry entry) {
  311. int usage = entry.getUsage();
  312. CocoDescriptionEntry e = entry;
  313. while ( e != null && !e.usageExplicit() )
  314. e = e.getParent();
  315. if ( e != null )
  316. usage = e.getUsage();
  317. return usage;
  318. }
  319. /**
  320. * Check name of description entry. Makes sure it is not blank nor a
  321. * duplicate. If name is "filler" (case ignored) it is made unique by
  322. * tacking on a number after it. Same case with "blank".
  323. * If name contains a high-level qualifier (HLQ) token, do the same.
  324. *
  325. * @param entry The description entry to validate
  326. *
  327. * @throws java.lang.IllegalArgumentException if the entry cannot be
  328. * validated in this data model
  329. */
  330. private void validateName(CocoDescriptionEntry entry)
  331. throws IllegalArgumentException {
  332. /* name can't be null or blank */
  333. String name = entry.getName();
  334. if (name == null || "".equals(name.trim())) {
  335. name = "BLANK";
  336. }
  337. name = name.toUpperCase();
  338. /* name cannot be FILLER{n} or BLANK{n}, where {n} is some integer */
  339. if (name.startsWith("FILLER") && !name.equalsIgnoreCase("FILLER")) {
  340. int at = 5;
  341. while (++at < name.length()) {
  342. if (!Character.isDigit(name.charAt(at))) {
  343. break;
  344. }
  345. }
  346. if (name.length() == at) {
  347. Message msg = MessageCatalog.getMessage("CCCB4105");
  348. String text = msg.formatText(new Object[] {
  349. name
  350. });
  351. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  352. throw new IllegalArgumentException(text);
  353. }
  354. }
  355. if (name.startsWith("BLANK") && !name.equalsIgnoreCase("BLANK")) {
  356. int at = 4;
  357. while (++at < name.length()) {
  358. if (!Character.isDigit(name.charAt(at))) {
  359. break;
  360. }
  361. }
  362. if (name.length() == at) {
  363. Message msg = MessageCatalog.getMessage("CCCB4106");
  364. String text = msg.formatText(new Object[] {
  365. name
  366. });
  367. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  368. throw new IllegalArgumentException(text);
  369. }
  370. }
  371. // FILLER and BLANK is globally unique
  372. /* filler items must be given unique names */
  373. if (name.equalsIgnoreCase("FILLER")) {
  374. entry.setName("FILLER" + ++mFillerCount);
  375. entry.setNameFiller(true);
  376. /* blank items must be given unique names */
  377. } else if (name.equalsIgnoreCase("BLANK")) {
  378. entry.setName("BLANK" + ++mBlankCount);
  379. entry.setNameBlank(true);
  380. /* names must be unique */
  381. } else {
  382. name = normalizeHlq(name);
  383. entry.setName(name);
  384. }
  385. }
  386. private String normalizeHlq(String name) {
  387. StringBuffer buffer = new StringBuffer(name.length());
  388. int hlqStart = name.indexOf(':');
  389. int start = 0;
  390. /* HLQ names must be normalized */
  391. while (hlqStart != -1) {
  392. int hlqEnd = name.indexOf(':', hlqStart + 1);
  393. if (hlqStart + 1 >= hlqEnd) {
  394. Message msg = MessageCatalog.getMessage("CCCB4107");
  395. String text = msg.formatText(new Object[] {
  396. name
  397. });
  398. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  399. throw new IllegalArgumentException(text);
  400. } else {
  401. String hlqName =
  402. name.substring(hlqStart, ++hlqEnd).toUpperCase();
  403. if (!mHlqs.containsKey(hlqName)) {
  404. mHlqs.put(hlqName, new Integer(mHlqs.size() + 1));
  405. }
  406. int hlqNum = ((Integer) mHlqs.get(hlqName)).intValue();
  407. buffer.append(name.substring(start, hlqStart) + "HLQ" + hlqNum);
  408. start = hlqEnd;
  409. hlqStart = name.indexOf(':', start);
  410. }
  411. }
  412. buffer.append(name.substring(start));
  413. return buffer.toString();
  414. }
  415. /**
  416. * Retrieve reference to model's record-level entry.
  417. *
  418. * @return Reference to the first entry ever added successfully to
  419. * the model, or an implicit level-01 (record) entry if no
  420. * entry has ever been added.
  421. */
  422. public CocoDescriptionEntry getRoot() {
  423. return mRootEntry;
  424. }
  425. /**
  426. * Retrieve reference to a specific entry added to the model.
  427. *
  428. * @param name Name of description entry to get
  429. *
  430. * @return The named description entry, or null if that entry does not
  431. * exist in the model
  432. */
  433. // the use of this method is to be reviewed - for now - it is not used
  434. public CocoDescriptionEntry getEntry(String name, String[] qualifiers) {
  435. // this method currently is called from
  436. // parseOccursClause() where the raw data-name is passed in
  437. // to lookup the entry that is used as the target
  438. // of clause DEPENDING ON <data-name>
  439. if (name == null) {
  440. return null;
  441. }
  442. if (mRootEntry.getName().equalsIgnoreCase(name)
  443. || name.equalsIgnoreCase(mRootEntry.getName())) {
  444. return mRootEntry;
  445. }
  446. // the raw name can come in as a simple name or a qualified name
  447. // before we are sure about the syntax of qualified name
  448. // let's deal with simple name first
  449. // the entry should already have
  450. // its name and level
  451. name = normalizeHlq(name);
  452. CocoDescriptionEntry match = null;
  453. ListIterator it = mEntries.listIterator();
  454. //name = (String) mNames.get(name);
  455. if (name != null) {
  456. while ((match == null) && it.hasNext()) {
  457. CocoDescriptionEntry entry = (CocoDescriptionEntry) it.next();
  458. if (name.equalsIgnoreCase(entry.getName())) {
  459. match = entry;
  460. }
  461. }
  462. }
  463. return match;
  464. }
  465. /**
  466. * Find a redefining item's redefined entry.
  467. *
  468. * @param redefiner Redefining item
  469. * @param name Redefined item's name
  470. *
  471. * @return The redefined entry, or <code>null</code> if it could not
  472. * be found.
  473. */
  474. public CocoDescriptionEntry findRedefineTarget(
  475. CocoDescriptionEntry redefiner, String name) {
  476. CocoDescriptionEntry target = null;
  477. // name mapping is no longer needed
  478. //String realName = (String) mNames.get(name.toUpperCase());
  479. // since we do not rename an original name for its global uniqueness
  480. // the redefined target should be resolved here;
  481. // the renaming for global uniqueness happens later just before
  482. // OTD gen
  483. String realName = name.toUpperCase();
  484. int ix = mEntries.size() - 1;
  485. // scan the entries from the lowest containing scope
  486. if (realName != null) {
  487. while (ix >= 0) {
  488. CocoDescriptionEntry last =
  489. (CocoDescriptionEntry) mEntries.get(ix--);
  490. int lastLevel = last.getLevel();
  491. int level = redefiner.getLevel();
  492. if (lastLevel < level) {
  493. break;
  494. }
  495. else if (lastLevel == level) {
  496. // use original name instead of name, Open-ESB issue 2272
  497. if (last.getOriginalName().equalsIgnoreCase(realName)) {
  498. target = last;
  499. break;
  500. }
  501. }
  502. }
  503. }
  504. return target;
  505. }
  506. /**
  507. * used for testing purposes. outputs trace info about model.
  508. *
  509. * @param outStream Outlet to which trace info is sent
  510. */
  511. public void toStream(PrintStream outStream) {
  512. ListIterator it = mEntries.listIterator();
  513. while (it.hasNext()) {
  514. CocoDescriptionEntry entry = (CocoDescriptionEntry) it.next();
  515. if (entry.isComment()) {
  516. outStream.print("**COMMENT**");
  517. } else {
  518. if (entry.isContinuation()) {
  519. outStream.print("- ");
  520. } else {
  521. outStream.print(" ");
  522. }
  523. outStream.print(entry.getIndicatorValue() + " ");
  524. outStream.print(entry.getLevel() + " ");
  525. outStream.print(entry.getName() + " ");
  526. outStream.print("USAGE " + entry.getUsage() + " ");
  527. if (entry.isBlankWhenZero()) {
  528. outStream.print("BLANK ");
  529. }
  530. if (entry.isJustified()) {
  531. outStream.print("JUST ");
  532. }
  533. String picture = entry.getPicture();
  534. if (!picture.equals("")) {
  535. outStream.print("PIC " + picture + " ");
  536. }
  537. if (entry.isRedefinition()) {
  538. outStream.print("REDEFINES "
  539. + entry.getRedefinedTarget().getName() + " ");
  540. }
  541. if (entry.getMinimumOccurs() > 1
  542. && entry.getMaximumOccurs() > 1) {
  543. outStream.print("OCCURS " + entry.getMinimumOccurs() + " ");
  544. if (entry.getMaximumOccurs() > entry.getMinimumOccurs()) {
  545. outStream.print("TO " + entry.getMaximumOccurs() + " ");
  546. }
  547. }
  548. CocoDescriptionEntry occursEntry = entry.getOccursOn();
  549. if (occursEntry != null) {
  550. outStream.print(
  551. "DEPENDS ON " + occursEntry.getName() + " ");
  552. List qualifiers = occursEntry.getDependOnNameQualifiers();
  553. if ( qualifiers != null && qualifiers.size() > 0 ) {
  554. for ( int i = 0; i < qualifiers.size(); i++ ) {
  555. outStream.print(" OF " + qualifiers.get(i));
  556. }
  557. }
  558. }
  559. }
  560. outStream.println();
  561. }
  562. outStream.flush();
  563. }
  564. /**
  565. * check all the base name conflicts and make them unique
  566. * note that name conflict in the same scope (same level number under a
  567. * group item) or across level number hierarchy should be name-mangled so
  568. * that they are all unique - otherwise, the name conflicts will cause
  569. * type conflict at OTD gen time (this issue might be resolved at OTD gen
  570. * time but we prefer to resolve it here anyway)
  571. */
  572. public void makeBaseNamesUnique() {
  573. Vector l = null;
  574. int suffix_count = 0;
  575. CocoDescriptionEntry entry = null;
  576. Iterator it = this.mBaseNames.keySet().iterator();
  577. if ( it == null )
  578. return;
  579. while ( it.hasNext() ) {
  580. String key = (String)it.next();
  581. l = (Vector)this.mBaseNames.get(key);
  582. if ( l == null ) {
  583. // fatal error
  584. Message msg = MessageCatalog.getMessage("CCCB4227");
  585. String text = msg.formatText(new Object[] {
  586. "Resolving name conflicts after copy book parsing "
  587. + "and before OTD generation.",
  588. "CocoDataModel.makeBaseNamesUnique()",
  589. "No entry found for registered base name : " + key
  590. });
  591. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  592. throw new IllegalArgumentException(text);
  593. }
  594. // mangle the base name for each entry in the list by suffixing it
  595. // with an under scure and a global index - this won't conflict
  596. // with existing data name since under score is not a cobol char.
  597. if ( l.size() > 1 ) {
  598. // the first one alway keep its name
  599. // so skip l[0] and rename l[1] - l[n]
  600. for ( int i = 1; i < l.size(); i++ ) {
  601. entry = (CocoDescriptionEntry)l.get(i);
  602. entry.setName(entry.getName() + "_" + suffix_count++);
  603. }
  604. }
  605. }
  606. }
  607. /**
  608. * resolve all the OCCURS that has forward referencing DEPENDING ON ...
  609. */
  610. public void resolveOccurs() {
  611. if ( this.mUnresolvedOccurs != null
  612. && this.mUnresolvedOccurs.size() > 0 ) {
  613. int cnt = this.mUnresolvedOccurs.size();
  614. CocoDescriptionEntry entry = null;
  615. String baseName = null;
  616. List qualifiers = null;
  617. for ( int i = 0; i < cnt; i++ ) {
  618. entry = (CocoDescriptionEntry)this.mUnresolvedOccurs.get(i);
  619. qualifiers = entry.getDependOnNameQualifiers();
  620. baseName = entry.getDependOnName();
  621. if ( baseName != null )
  622. baseName = baseName.toUpperCase();
  623. String fqName = getQualifiedName(qualifiers, baseName);
  624. List depends = this.lookupEntry(qualifiers, baseName, 2);
  625. if ( depends == null || depends.size() == 0 ) {
  626. // dangling reference
  627. Message msg = MessageCatalog.getMessage("CCCB4226");
  628. String text = msg.formatText(new Object[] {
  629. baseName,
  630. fqName
  631. });
  632. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  633. throw new IllegalArgumentException(text);
  634. }
  635. else if ( depends.size() >= 2 ) {
  636. // ambiguity - there are more than one entry that match
  637. // the name
  638. Message msg = MessageCatalog.getMessage("CCCB4225");
  639. String text = msg.formatText(
  640. new Object[] {
  641. baseName,
  642. fqName,
  643. ((CocoDescriptionEntry) depends.get(0)).getInfo(),
  644. ((CocoDescriptionEntry) depends.get(1)).getInfo()
  645. });
  646. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  647. throw new IllegalArgumentException(text);
  648. }
  649. // now resolved
  650. // further validate
  651. CocoDescriptionEntry dependsObj =
  652. (CocoDescriptionEntry)depends.get(0);
  653. if (dependsObj.getMinimumOccurs() != 1
  654. && dependsObj.getMaximumOccurs() != 1) {
  655. Message msg = MessageCatalog.getMessage("CCCB4211");
  656. String text = msg.formatText(new Object[] {
  657. dependsObj.getName()
  658. });
  659. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  660. throw new IllegalArgumentException(text);
  661. } else if (dependsObj.getJavaType()
  662. == CocoDescriptionEntry.JavaType.LONG
  663. || dependsObj.getJavaType()
  664. == CocoDescriptionEntry.JavaType.BIGDEC) {
  665. Message msg = MessageCatalog.getMessage("CCCB4212");
  666. String text = msg.formatText(new Object[] {
  667. dependsObj.getName()
  668. });
  669. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  670. throw new IllegalArgumentException(text);
  671. } else if (dependsObj.getJavaType()
  672. != CocoDescriptionEntry.JavaType.INT) {
  673. Message msg = MessageCatalog.getMessage("CCCB4213");
  674. String text = msg.formatText(new Object[] {
  675. dependsObj.getName()
  676. });
  677. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  678. throw new IllegalArgumentException(text);
  679. }
  680. entry.setDependsOnTarget(dependsObj);
  681. }
  682. }
  683. }
  684. /**
  685. * helper
  686. * @param qualifiers
  687. * @param base
  688. * @return
  689. */
  690. private String getQualifiedName(List qualifiers, String base) {
  691. StringBuffer sb = new StringBuffer(base);
  692. if ( qualifiers != null && qualifiers.size() > 0 ) {
  693. for ( int i = 0; i < qualifiers.size(); i++ ) {
  694. sb.append(" OF ").append(qualifiers.get(i));
  695. }
  696. }
  697. return sb.toString();
  698. }
  699. /**
  700. * return a list of matching entries in the model
  701. * @param qualifiers - qualifiers for the base name
  702. * @param name - the base name
  703. * @param count - return only the first <code>count</code> number of entries
  704. * @return the list of entries that its FQN match the given qualified name.
  705. */
  706. private List lookupEntry(List qualifiers, String name, int count) {
  707. List result = null;
  708. String currentName = null;
  709. Iterator it = this.mNames.keySet().iterator();
  710. CocoDescriptionEntry parent, entry = null;
  711. Vector entry_list = null;
  712. int cnt = 0;
  713. boolean matched = true;
  714. while ( it.hasNext() ) {
  715. currentName = (String)it.next();
  716. if ( currentName.endsWith(name) ) {
  717. // only when the FQN ends with the given base name
  718. // we look into the entries further
  719. matched = true;
  720. // get the entry and check the base name
  721. entry_list = (Vector)(this.mNames.get(currentName));
  722. // in the entry_list, all the entry has same FQN - so check
  723. // one is check all
  724. entry = (CocoDescriptionEntry)entry_list.get(0);
  725. if ( name.equalsIgnoreCase(entry.getName()) ) {
  726. // base name match
  727. if ( qualifiers != null && qualifiers.size() > 0 ) {
  728. // also need to match qualifiers
  729. CocoDescriptionEntry tempEntry = entry;
  730. for ( int j = 0; j < qualifiers.size(); j++ ) {
  731. parent = tempEntry.getParent();
  732. if ( parent == null ) {
  733. // path does not match the qualifiers -
  734. // not a match
  735. matched = false;
  736. break;
  737. }
  738. String qualifierName = (String)qualifiers.get(j);
  739. if ( qualifierName != null
  740. && parent.getName().equalsIgnoreCase(
  741. qualifierName.toUpperCase())) {
  742. // still match
  743. tempEntry = parent;
  744. }
  745. else {
  746. // no longer match
  747. matched = false;
  748. break;
  749. }
  750. }
  751. }
  752. // remember those matched
  753. if ( matched ) {
  754. if ( result == null )
  755. result = new ArrayList();
  756. result.addAll(entry_list);
  757. cnt += entry_list.size();
  758. if ( cnt >= count )
  759. break;
  760. }
  761. }
  762. }
  763. }
  764. return result;
  765. }
  766. /**
  767. * register an unresolved entry (OCCURS ... DEPENDING ON <data-name>)
  768. * @param entry
  769. */
  770. public void addOccurs(CocoDescriptionEntry entry) {
  771. if ( this.mUnresolvedOccurs == null )
  772. this.mUnresolvedOccurs = new ArrayList();
  773. this.mUnresolvedOccurs.add(entry);
  774. }
  775. /**
  776. * register an entry into base name collision table
  777. * - later will be used to resolve these conflicts
  778. * by rename them (name mangling so that they become globally unique)
  779. * @param entry
  780. */
  781. private void registerBaseName(CocoDescriptionEntry entry) {
  782. Vector l = null;
  783. if ( this.mBaseNames.containsKey(entry.getName()) ) {
  784. // register the entry with its base name as key
  785. l = (Vector)this.mBaseNames.get(entry.getName());
  786. if ( l == null ) {
  787. // fatal error
  788. Message msg = MessageCatalog.getMessage("CCCB4227");
  789. String text = msg.formatText(new Object[] {
  790. "Registering base name.",
  791. "CocoDataModel.registerBaseName()",
  792. "No entry found for registered base name : "
  793. + entry.getName()
  794. });
  795. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  796. throw new IllegalArgumentException(text);
  797. }
  798. int sz = l.size();
  799. l.add(sz, entry);
  800. }
  801. else {
  802. // first time this base name encountered
  803. l = new Vector(1);
  804. l.add(0, entry);
  805. this.mBaseNames.put(entry.getName(), l);
  806. }
  807. }
  808. public void registerFQN(CocoDescriptionEntry entry) {
  809. if ( this.mNames.containsKey(entry.getFQN()) ) {
  810. Vector l = (Vector)mNames.get(entry.getFQN());
  811. if ( l != null ) {
  812. int sz = l.size();
  813. l.add(sz, entry);
  814. }
  815. else {
  816. // fatal error
  817. Message msg = MessageCatalog.getMessage("CCCB4227");
  818. String text = msg.formatText(new Object[] {
  819. "Registering FQN - fully qualified name.",
  820. "CocoDataModel.registerFQN()",
  821. "No entry found for registered FQN : " + entry.getFQN()
  822. });
  823. mErrorMgr.log(ErrorManager.Severity.ERROR, null, text);
  824. throw new IllegalArgumentException(text);
  825. }
  826. }
  827. else {
  828. // first comer
  829. // assume most of time - no dup names
  830. List l = new Vector(1);
  831. l.add(0, entry);
  832. mNames.put(entry.getFQN(), l);
  833. }
  834. }
  835. }