Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

AjcSpecXmlReader.java 22KB

21 лет назад
21 лет назад
18 лет назад
21 лет назад
18 лет назад
21 лет назад
21 лет назад
4 лет назад
21 лет назад
4 лет назад
21 лет назад
4 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
21 лет назад
19 лет назад
19 лет назад
19 лет назад
21 лет назад
21 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. /* *******************************************************************
  2. * Copyright (c) 1999-2001 Xerox Corporation,
  3. * 2002 Palo Alto Research Center, Incorporated (PARC),
  4. * 2003 Contributors.
  5. * All rights reserved.
  6. * This program and the accompanying materials are made available
  7. * under the terms of the Eclipse Public License v1.0
  8. * which accompanies this distribution and is available at
  9. * http://www.eclipse.org/legal/epl-v10.html
  10. *
  11. * Contributors:
  12. * Xerox/PARC initial implementation
  13. * Wes Isberg resolver
  14. * ******************************************************************/
  15. package org.aspectj.testing.xml;
  16. //import java.util.Vector;
  17. import java.io.File;
  18. import java.io.FileInputStream;
  19. import java.io.FileOutputStream;
  20. import java.io.FileWriter;
  21. import java.io.IOException;
  22. import java.io.PrintWriter;
  23. import org.apache.commons.digester.Digester;
  24. import org.aspectj.bridge.AbortException;
  25. import org.aspectj.bridge.IMessage;
  26. import org.aspectj.bridge.ISourceLocation;
  27. import org.aspectj.bridge.MessageUtil;
  28. import org.aspectj.bridge.SourceLocation;
  29. import org.aspectj.testing.harness.bridge.AjcTest;
  30. import org.aspectj.testing.harness.bridge.CompilerRun;
  31. import org.aspectj.testing.harness.bridge.DirChanges;
  32. import org.aspectj.testing.harness.bridge.IncCompilerRun;
  33. import org.aspectj.testing.harness.bridge.JavaRun;
  34. import org.aspectj.testing.harness.bridge.Sandbox;
  35. import org.aspectj.testing.harness.bridge.Validator;
  36. import org.aspectj.testing.util.RunUtils;
  37. import org.aspectj.util.LangUtil;
  38. import org.xml.sax.EntityResolver;
  39. import org.xml.sax.InputSource;
  40. import org.xml.sax.SAXException;
  41. /**
  42. * Read an ajc test specification in xml form.
  43. * Input files should comply with DOCTYPE
  44. */
  45. public class AjcSpecXmlReader {
  46. /*
  47. * To add new elements or attributes:
  48. * - update the DOCTYPE
  49. * - update setupDigester(..)
  50. * - new sub-elements should be created
  51. * - new attributes should have values set as bean properties
  52. * (possibly by mapping names)
  53. * - new sub-elements should be added to parents
  54. * => the parents need the add method - e.g., add{foo}({foo} toadd)
  55. * - add tests
  56. * - add compile-time checks for mapping APIs in
  57. * setupDigesterComipileTimeCheck
  58. * - when adding an attribute set by bean introspection,
  59. * add to the list returned by expectedProperties()
  60. * - update any client writers referring to the DOCTYPE, as necessary.
  61. * - the parent IXmlWriter should delegate to the child component
  62. * as IXmlWriter (or write the subelement itself)
  63. *
  64. * Debugging
  65. * - use logLevel = 2 for tracing
  66. * - common mistakes
  67. * - dtd has to match input
  68. * - no rule defined (or misdefined) so element ignored
  69. * - property read-only (?)
  70. */
  71. // private static final String EOL = "\n";
  72. /** presumed relative-path to dtd file for any XML files written by writeSuiteToXmlFile */
  73. public static final String DTD_PATH = "../tests/ajcTestSuite.dtd";
  74. /** expected doc type of AjcSpec XML files */
  75. public static final String DOCTYPE = "<!DOCTYPE "
  76. + AjcTest.Suite.Spec.XMLNAME + " SYSTEM \"" + DTD_PATH + "\">";
  77. private static final AjcSpecXmlReader ME
  78. = new AjcSpecXmlReader();
  79. /** @return shared instance */
  80. public static final AjcSpecXmlReader getReader() {
  81. return ME;
  82. }
  83. public static void main(String[] a) throws IOException {
  84. writeDTD(new File("../tests/ajcTestSuite2.dtd"));
  85. }
  86. /**
  87. * Write a DTD to dtdFile.
  88. * @deprecated
  89. * @param dtdFile the File to write to
  90. */
  91. public static void writeDTD(File dtdFile) throws IOException {
  92. LangUtil.throwIaxIfNull(dtdFile, "dtdFile");
  93. PrintWriter out = new PrintWriter(new FileWriter(dtdFile));
  94. try {
  95. out.println("<!-- document type for ajc test suite - see "
  96. + AjcSpecXmlReader.class.getName() + " -->");
  97. //out.println(getDocType());
  98. } finally {
  99. out.close();
  100. }
  101. }
  102. private static final String[] LOG = new String[] {"info", "debug", "trace" };
  103. // XXX logLevel n>0 causes JUnit tests to fail!
  104. private int logLevel = 0; // use 2 for tracing
  105. private AjcSpecXmlReader() {}
  106. /** @param level 0..2, info..trace */
  107. public void setLogLevel(int level) {
  108. if (level < 0) {
  109. level = 0;
  110. }
  111. if (level > 2) {
  112. level = 2;
  113. }
  114. logLevel = level;
  115. }
  116. /**
  117. * Print an IXmlWritable to the output file
  118. * with our leader and DOCTYPE.
  119. * @param output the File to write to - overwritten
  120. * @param tests the List of IXmlWritable to write
  121. * @return null if no warnings detected, warnings otherwise
  122. */
  123. public String writeSuiteToXmlFile(File output, IXmlWritable topNode) throws IOException {
  124. PrintWriter writer = new PrintWriter(new FileOutputStream(output));
  125. XMLWriter printSink = new XMLWriter(writer);
  126. writer.println("");
  127. writer.println(AjcSpecXmlReader.DOCTYPE);
  128. writer.println("");
  129. topNode.writeXml(printSink);
  130. writer.close();
  131. String parent = output.getParent();
  132. if (null == parent) {
  133. parent = ".";
  134. }
  135. String dtdPath = parent + "/" + DTD_PATH;
  136. File dtdFile = new File(dtdPath);
  137. if (!dtdFile.canRead()) {
  138. return "expecting dtd file: " + dtdFile.getPath();
  139. }
  140. return null;
  141. }
  142. /**
  143. * Read the specifications for a suite of AjcTest from an XML file.
  144. * This also sets the suite dir in the specification.
  145. * @param file the File must be readable, comply with DOCTYPE.
  146. * @return AjcTest.Suite.Spec read from file
  147. * @see setLogLevel(int)
  148. */
  149. public AjcTest.Suite.Spec readAjcSuite(File file) throws IOException, AbortException {
  150. // setup loggers for digester and beanutils...
  151. System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog"); // XXX
  152. System.setProperty("org.apache.commons.logging.simplelog.defaultlog", LOG[logLevel]); // trace debug XXX
  153. final Digester digester = makeDigester(file);
  154. SuiteHolder holder = new SuiteHolder();
  155. digester.push(holder);
  156. FileInputStream input = new FileInputStream(file);
  157. try {
  158. digester.parse(input);
  159. } catch (SAXException e) {
  160. MessageUtil.fail("parsing " + file, e);
  161. } finally {
  162. if (null != input) {
  163. input.close();
  164. input = null;
  165. }
  166. }
  167. AjcTest.Suite.Spec result = holder.spec;
  168. if (null != result) {
  169. file = file.getAbsoluteFile();
  170. result.setSourceLocation(new SourceLocation(file, 1));
  171. File suiteDir = file.getParentFile();
  172. if (null == suiteDir) {
  173. // should not be the case if absolute
  174. suiteDir = new File("."); // user.dir?
  175. }
  176. result.setSuiteDirFile(suiteDir);
  177. if (result.runtime.isVerbose()) { // XXX hack fixup
  178. RunUtils.enableVerbose(result);
  179. }
  180. }
  181. return result;
  182. }
  183. private Digester makeDigester(final File suiteFile) {
  184. // implement EntityResolver directly; set is failing
  185. Digester result = new Digester() {
  186. final SuiteResolver resolver = new SuiteResolver(suiteFile);
  187. public InputSource resolveEntity(
  188. String publicId,
  189. String systemId)
  190. throws SAXException {
  191. return resolver.resolveEntity(publicId, systemId);
  192. }
  193. };
  194. setupDigester(result);
  195. return result;
  196. }
  197. /** set up the mapping between the xml and Java. */
  198. private void setupDigester(Digester digester) {
  199. // XXX supply sax parser to ignore white space?
  200. digester.setValidating(true);
  201. // try {
  202. // // this is the correct approach, but the commons parser
  203. // // fails to accept a second, overriding registration - see
  204. // // http://lists.xml.org/archives/xml-dev/200111/msg00959.html
  205. // digester.getXMLReader().setEntityResolver(new SuiteResolver(suiteFile));
  206. // } catch (SAXException e) {
  207. // System.err.println("unable to set entity resolver");
  208. // e.printStackTrace(System.err);
  209. // }
  210. // element names come from the element components
  211. final String suiteX = AjcTest.Suite.Spec.XMLNAME;
  212. final String ajctestX = suiteX + "/" + AjcTest.Spec.XMLNAME;
  213. final String compileX = ajctestX + "/" + CompilerRun.Spec.XMLNAME;
  214. final String inccompileX = ajctestX + "/" + IncCompilerRun.Spec.XMLNAME;
  215. final String runX = ajctestX + "/" + JavaRun.Spec.XMLNAME;
  216. final String dirchangesX = "*/" + DirChanges.Spec.XMLNAME;
  217. final String messageX = "*/" + SoftMessage.XMLNAME;
  218. final String messageSrcLocX = messageX + "/" +SoftSourceLocation.XMLNAME;
  219. // ---- each sub-element needs to be created
  220. // handle messages the same at any level
  221. digester.addObjectCreate(suiteX, AjcTest.Suite.Spec.class.getName());
  222. digester.addObjectCreate(ajctestX, AjcTest.Spec.class.getName());
  223. digester.addObjectCreate(compileX, CompilerRun.Spec.class.getName());
  224. //digester.addObjectCreate(compileX + "/file", AbstractRunSpec.WrapFile.class.getName());
  225. digester.addObjectCreate(inccompileX, IncCompilerRun.Spec.class.getName());
  226. digester.addObjectCreate(runX, JavaRun.Spec.class.getName());
  227. digester.addObjectCreate(messageX, SoftMessage.class.getName());
  228. digester.addObjectCreate(messageSrcLocX, SoftSourceLocation.class.getName());
  229. digester.addObjectCreate(dirchangesX, DirChanges.Spec.class.getName());
  230. // ---- set bean properties for sub-elements created automatically
  231. // -- some remapped - warnings
  232. // - if property exists, map will not be used
  233. digester.addSetProperties(suiteX); // ok to have suite messages and global suite options, etc.
  234. digester.addSetProperties(ajctestX,
  235. new String[] { "title", "dir", "pr"},
  236. new String[] { "description", "testDirOffset", "bugId"});
  237. digester.addSetProperties(compileX,
  238. new String[] { "files", "argfiles"},
  239. new String[] { "paths", "argfiles"});
  240. digester.addSetProperties(compileX + "/file");
  241. digester.addSetProperties(inccompileX, "classes", "paths");
  242. digester.addSetProperties(runX,
  243. new String[] { "class", "vm", "skipTester", "fork", "vmargs", "aspectpath", "module"},
  244. new String[] { "className", "javaVersion", "skipTester", "fork", "vmArgs", "aspectpath", "module"});
  245. digester.addSetProperties(dirchangesX);
  246. digester.addSetProperties(messageX);
  247. digester.addSetProperties(messageSrcLocX, "line", "lineAsString");
  248. digester.addSetProperties(messageX, "kind", "kindAsString");
  249. digester.addSetProperties(messageX, "line", "lineAsString");
  250. //digester.addSetProperties(messageX, "details", "details");
  251. // only file subelement of compile uses text as path... XXX vestigial
  252. digester.addCallMethod(compileX + "/file", "setFile", 0);
  253. // ---- when subelements are created, add to parent
  254. // add ajctest to suite, runs to ajctest, files to compile, messages to any parent...
  255. // the method name (e.g., "addSuite") is in the parent (SuiteHolder)
  256. // the class (e.g., AjcTest.Suite.Spec) refers to the type of the object created
  257. digester.addSetNext(suiteX, "addSuite", AjcTest.Suite.Spec.class.getName());
  258. digester.addSetNext(ajctestX, "addChild", AjcTest.Spec.class.getName());
  259. digester.addSetNext(compileX, "addChild", CompilerRun.Spec.class.getName());
  260. digester.addSetNext(inccompileX, "addChild", IncCompilerRun.Spec.class.getName());
  261. digester.addSetNext(runX, "addChild", JavaRun.Spec.class.getName());
  262. //digester.addSetNext(compileX + "/file", "addWrapFile", AbstractRunSpec.WrapFile.class.getName());
  263. digester.addSetNext(messageX, "addMessage", IMessage.class.getName());
  264. // setSourceLocation is for the inline variant
  265. // addSourceLocation is for the extra
  266. digester.addSetNext(messageSrcLocX, "addSourceLocation", ISourceLocation.class.getName());
  267. digester.addSetNext(dirchangesX, "addDirChanges", DirChanges.Spec.class.getName());
  268. // can set parent, but prefer to have "knows-about" flow down only...
  269. }
  270. // ------------------------------------------------------------ testing code
  271. /**
  272. * Get expected bean properties for introspection tests.
  273. * This should return an expected property for every attribute in DOCTYPE,
  274. * using any mapped-to names from setupDigester.
  275. */
  276. static BProps[] expectedProperties() {
  277. return new BProps[]
  278. {
  279. new BProps(AjcTest.Suite.Spec.class,
  280. new String[] { "suiteDir"}), // verbose removed
  281. new BProps(AjcTest.Spec.class,
  282. new String[] { "description", "testDirOffset", "bugId"}),
  283. // mapped from { "title", "dir", "pr"}
  284. new BProps(CompilerRun.Spec.class,
  285. new String[] { "files", "options",
  286. "staging", "badInput", "reuseCompiler", "includeClassesDir",
  287. "argfiles", "aspectpath", "classpath", "extdirs",
  288. "sourceroots", "xlintfile", "outjar"}),
  289. new BProps(IncCompilerRun.Spec.class,
  290. new String[] { "tag" }),
  291. new BProps(JavaRun.Spec.class,
  292. new String[] { "className", "skipTester", "options",
  293. "javaVersion", "errStreamIsError", "outStreamIsError",
  294. "fork", "vmArgs", "aspectpath"}),
  295. // mapped from { "class", ...}
  296. new BProps(DirChanges.Spec.class,
  297. new String[] { "added", "removed", "updated", "unchanged", "dirToken", "defaultSuffix"}),
  298. // new BProps(AbstractRunSpec.WrapFile.class,
  299. // new String[] { "path"}),
  300. new BProps(SoftMessage.class,
  301. new String[] { "kindAsString", "lineAsString", "text", "details", "file"})
  302. // mapped from { "kind", "line", ...}
  303. };
  304. }
  305. /**
  306. * This is only to do compile-time checking for the APIs impliedly
  307. * used in setupDigester(..).
  308. * The property setter checks are redundant with tests based on
  309. * expectedProperties().
  310. */
  311. private static void setupDigesterCompileTimeCheck() {
  312. if (true) { throw new Error("never invoked"); }
  313. AjcTest.Suite.Spec suite = new AjcTest.Suite.Spec();
  314. AjcTest.Spec test = new AjcTest.Spec();
  315. Sandbox sandbox = null;
  316. Validator validator = null;
  317. // AjcTest ajctest = new AjcTest(test, sandbox, validator);
  318. // ajctest.addRunSpec((AbstractRunSpec) null);
  319. //// test.makeIncCompilerRun((IncCompilerRun.Spec) null);
  320. //// test.makeJavaRun((JavaRun.Spec) null);
  321. // ajctest.setDescription((String) null);
  322. // ajctest.setTestBaseDirOffset((String) null);
  323. // ajctest.setBugId((String) null);
  324. // ajctest.setTestSourceLocation((ISourceLocation) null);
  325. CompilerRun.Spec crunSpec = new CompilerRun.Spec();
  326. crunSpec.addMessage((IMessage) null);
  327. // XXX crunSpec.addSourceLocation((ISourceLocation) null);
  328. // crunSpec.addWrapFile((AbstractRunSpec.WrapFile) null);
  329. crunSpec.setOptions((String) null);
  330. crunSpec.setPaths((String) null);
  331. crunSpec.setIncludeClassesDir(false);
  332. crunSpec.setReuseCompiler(false);
  333. crunSpec.setXlintfile((String) null);
  334. crunSpec.setOutjar((String)null);
  335. IncCompilerRun.Spec icrunSpec = new IncCompilerRun.Spec();
  336. icrunSpec.addMessage((IMessage) null);
  337. icrunSpec.setTag((String) null);
  338. icrunSpec.setFresh(false);
  339. JavaRun.Spec jrunspec = new JavaRun.Spec();
  340. jrunspec.addMessage((IMessage) null);
  341. jrunspec.setClassName((String) null);
  342. jrunspec.addMessage((IMessage) null);
  343. // input s.b. interpretable by Boolean.valueOf(String)
  344. jrunspec.setSkipTester(true);
  345. jrunspec.setErrStreamIsError("false");
  346. jrunspec.setOutStreamIsError("false");
  347. jrunspec.setAspectpath("");
  348. jrunspec.setClasspath("");
  349. jrunspec.setFork(false);
  350. jrunspec.setLTW("false");
  351. jrunspec.setException("Error");
  352. DirChanges.Spec dcspec = new DirChanges.Spec();
  353. dcspec.setAdded((String) null);
  354. dcspec.setRemoved((String) null);
  355. dcspec.setUpdated((String) null);
  356. dcspec.setDefaultSuffix((String) null);
  357. dcspec.setDirToken((String) null);
  358. SoftMessage m = new SoftMessage();
  359. m.setSourceLocation((ISourceLocation) null);
  360. m.setText((String) null);
  361. m.setKindAsString((String) null);
  362. m.setDetails((String) null);
  363. SoftSourceLocation sl = new SoftSourceLocation();
  364. sl.setFile((String) null);
  365. sl.setLine((String) null);
  366. sl.setColumn((String) null);
  367. sl.setEndLine((String) null);
  368. // add attribute setters to validate?
  369. }
  370. /** top element on Digester stack holds the test suite */
  371. public static class SuiteHolder {
  372. AjcTest.Suite.Spec spec;
  373. public void addSuite(AjcTest.Suite.Spec spec) {
  374. this.spec = spec;
  375. }
  376. }
  377. /** hold class/properties association for testing */
  378. static class BProps {
  379. final Class cl;
  380. final String[] props;
  381. BProps(Class cl, String[] props) {
  382. this.cl = cl;
  383. this.props = props;
  384. }
  385. }
  386. /**
  387. * Find file NAME=="ajcTestSuite.dtd" from some reasonably-local
  388. * relative directories.
  389. * XXX bug: commons parser doesn't accept second registration,
  390. * so we override Digester's implementation instead.
  391. * XXX cannot JUnit test SuiteResolver since they run from
  392. * local directory with valid reference
  393. * XXX does not fix JDK 1.4 parser message "unable to resolve without base URI"
  394. * XXX should be able to just set BaseURI instead...
  395. */
  396. static class SuiteResolver implements EntityResolver {
  397. public static final String NAME = "ajcTestSuite.dtd";
  398. private static boolean isDir(File dir) {
  399. return ((null != dir) && dir.canRead() && dir.isDirectory());
  400. }
  401. private final File suiteFile;
  402. public SuiteResolver(File suiteFile) {
  403. this.suiteFile = suiteFile;
  404. }
  405. private String getPath(String id) {
  406. // first, try id relative to suite file
  407. final File suiteFileDir = suiteFile.getParentFile();
  408. if (isDir(suiteFileDir)) {
  409. String path = suiteFileDir.getPath()
  410. + "/" + id;
  411. File result = new File(path);
  412. if (result.canRead() && result.isFile()) {
  413. return result.getPath();
  414. }
  415. }
  416. // then try misc paths relative to suite file or current dir
  417. final File[] baseDirs = new File[]
  418. { suiteFileDir, new File(".")
  419. };
  420. final String[] locations = new String[]
  421. { ".", "..", "../tests", "../../tests",
  422. "../../../tests", "tests", "modules/tests"
  423. };
  424. File baseDir;
  425. for (int j = 0; j < baseDirs.length; j++) {
  426. baseDir = baseDirs[j];
  427. if (!isDir(baseDir)) {
  428. continue;
  429. }
  430. for (int i = 0; i < locations.length; i++) {
  431. File dir = new File(baseDir, locations[i]);
  432. if (isDir(dir)) {
  433. File temp = new File(dir, NAME);
  434. if (temp.isFile() && temp.canRead()) {
  435. return temp.getPath();
  436. }
  437. }
  438. }
  439. }
  440. return null;
  441. }
  442. public InputSource resolveEntity(
  443. String publicId,
  444. String systemId)
  445. throws SAXException {
  446. InputSource result = null;
  447. if ((null != systemId) &&
  448. systemId.endsWith(NAME)) {
  449. String path = getPath(systemId);
  450. if (null != path) {
  451. result = new InputSource(path);
  452. result.setSystemId(path);
  453. result.setPublicId(path);
  454. }
  455. }
  456. return result;
  457. }
  458. }
  459. }
  460. //private String getDocTypePath() {
  461. // String result = null;
  462. // if (null != suiteFile) {
  463. // FileReader fr = null;
  464. // try {
  465. // fr = new FileReader(suiteFile);
  466. // BufferedReader reader = new BufferedReader(fr);
  467. // String line;
  468. // while (null != (line = reader.readLine())) {
  469. // String upper = line.trim();
  470. // line = upper.toLowerCase();
  471. // if (line.startsWith("<")) {
  472. // if (line.startsWith("<!doctype ")) {
  473. // int start = line.indexOf("\"");
  474. // int end = line.lastIndexOf(NAME + "\"");
  475. // if ((0 < start) && (start < end)) {
  476. // return upper.substring(start+1,
  477. // end + NAME.length());
  478. // }
  479. // } else if (!line.startsWith("<?xml")) {
  480. // break; // something else...
  481. // }
  482. // }
  483. // }
  484. // } catch (IOException e) {
  485. // // ignore
  486. // } finally {
  487. // if (null != fr) {
  488. // try {
  489. // fr.close();
  490. // } catch (IOException e1) { // ignore
  491. // }
  492. // }
  493. // }
  494. // }
  495. // return null;
  496. //}