0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.nbbuild;
0043:
0044: import java.io.BufferedReader;
0045: import java.io.ByteArrayOutputStream;
0046: import java.io.File;
0047: import java.io.FileInputStream;
0048: import java.io.FileOutputStream;
0049: import java.io.FileReader;
0050: import java.io.IOException;
0051: import java.io.InputStream;
0052: import java.io.OutputStream;
0053: import java.io.Reader;
0054: import java.util.ArrayList;
0055: import java.util.Arrays;
0056: import java.util.HashMap;
0057: import java.util.HashSet;
0058: import java.util.Hashtable;
0059: import java.util.LinkedList;
0060: import java.util.List;
0061: import java.util.Map;
0062: import java.util.Set;
0063: import java.util.StringTokenizer;
0064: import java.util.jar.Attributes;
0065: import java.util.jar.JarFile;
0066: import java.util.regex.Matcher;
0067: import java.util.regex.Pattern;
0068: import java.util.zip.CRC32;
0069: import java.util.zip.ZipEntry;
0070: import java.util.zip.ZipInputStream;
0071: import java.util.zip.ZipOutputStream;
0072: import org.apache.tools.ant.BuildException;
0073: import org.apache.tools.ant.Project;
0074: import org.apache.tools.ant.Task;
0075: import org.w3c.dom.Document;
0076: import org.w3c.dom.Element;
0077: import org.xml.sax.InputSource;
0078: import org.xml.sax.SAXException;
0079:
0080: /**
0081: * Parse a projectized module's <code>nbproject/project.xml</code> and
0082: * define various useful Ant properties based on the result.
0083: * @author Jesse Glick
0084: */
0085: public final class ParseProjectXml extends Task {
0086:
0087: static final String PROJECT_NS = "http://www.netbeans.org/ns/project/1";
0088: static final String NBM_NS2 = "http://www.netbeans.org/ns/nb-module-project/2";
0089: static final String NBM_NS3 = "http://www.netbeans.org/ns/nb-module-project/3";
0090:
0091: static final int TYPE_NB_ORG = 0;
0092: static final int TYPE_SUITE = 1;
0093: static final int TYPE_STANDALONE = 2;
0094:
0095: private File project;
0096:
0097: /**
0098: * Set the NetBeans module project to work on.
0099: */
0100: public void setProject(File f) {
0101: project = f;
0102: }
0103:
0104: private File projectFile;
0105:
0106: /**
0107: * Another option is to directly point to project file.
0108: * Used only in unit testing.
0109: */
0110: public void setProjectFile(File f) {
0111: projectFile = f;
0112: }
0113:
0114: private File getProjectFile() {
0115: if (projectFile != null) {
0116: return projectFile;
0117: }
0118: return new File(new File(project, "nbproject"), "project.xml");
0119: }
0120:
0121: private String publicPackagesProperty;
0122:
0123: /**
0124: * Set the property to set a list of
0125: * OpenIDE-Module-Public-Packages to.
0126: */
0127: public void setPublicPackagesProperty(String s) {
0128: publicPackagesProperty = s;
0129: }
0130:
0131: private String friendsProperty;
0132:
0133: /**
0134: * Set the property to set a list of
0135: * OpenIDE-Module-Friends to.
0136: */
0137: public void setFriendsProperty(String s) {
0138: friendsProperty = s;
0139: }
0140:
0141: private String javadocPackagesProperty;
0142:
0143: /**
0144: * Set the property to set a list of public packages for Javadoc
0145: * to.
0146: */
0147: public void setJavadocPackagesProperty(String s) {
0148: javadocPackagesProperty = s;
0149: }
0150:
0151: private String moduleDependenciesProperty;
0152:
0153: /**
0154: * Set the property to set a list of
0155: * OpenIDE-Module-Module-Dependencies to, based on the list of
0156: * stated run-time dependencies.
0157: */
0158: public void setModuleDependenciesProperty(String s) {
0159: moduleDependenciesProperty = s;
0160: }
0161:
0162: private String codeNameBaseDashesProperty;
0163:
0164: /**
0165: * Set the property to set the module code name base (separated by
0166: * dashes not dots) to.
0167: */
0168: public void setCodeNameBaseDashesProperty(String s) {
0169: codeNameBaseDashesProperty = s;
0170: }
0171:
0172: private String codeNameBaseSlashesProperty;
0173:
0174: /**
0175: * Set the property to set the module code name base (separated by
0176: * slashes not dots) to.
0177: */
0178: public void setCodeNameBaseSlashesProperty(String s) {
0179: codeNameBaseSlashesProperty = s;
0180: }
0181:
0182: private String domainProperty;
0183:
0184: /**
0185: * Set the property to set the module's netbeans.org domain to.
0186: * Only applicable to modules in netbeans.org (i.e. no <path>).
0187: */
0188: public void setDomainProperty(String s) {
0189: domainProperty = s;
0190: }
0191:
0192: private String moduleClassPathProperty;
0193:
0194: /**
0195: * Set the property to set the computed module class path to,
0196: * based on the list of stated compile-time dependencies.
0197: */
0198: public void setModuleClassPathProperty(String s) {
0199: moduleClassPathProperty = s;
0200: }
0201:
0202: private String moduleRunClassPathProperty;
0203:
0204: /**
0205: * Set the property to set the computed module runtime class path to.
0206: * Currently identical to the regular class path with the exception
0207: * that original JARs are used, never public-package-only JARs.
0208: * XXX In the future should however reflect <run-dependency/>
0209: * rather than <compile-dependency/>
0210: */
0211: public void setModuleRunClassPathProperty(String s) {
0212: moduleRunClassPathProperty = s;
0213: }
0214:
0215: private File publicPackageJarDir;
0216:
0217: /**
0218: * Set the location of a directory in which to look for and create
0219: * JARs containing just the public packages of appropriate
0220: * compile-time dependencies.
0221: */
0222: public void setPublicPackageJarDir(File d) {
0223: publicPackageJarDir = d;
0224: }
0225:
0226: private String classPathExtensionsProperty;
0227:
0228: /**
0229: * Set the property to set the declared Class-Path attribute to.
0230: */
0231: public void setClassPathExtensionsProperty(String s) {
0232: classPathExtensionsProperty = s;
0233: }
0234:
0235: // test distribution path
0236: public static String testDistLocation;
0237:
0238: public static class TestType {
0239: private String name;
0240: private String folder;
0241: private String runtimeCP;
0242: private String compileCP;
0243: /** compilation dependency supported only unit tests
0244: */
0245: private String compileDep;
0246:
0247: public TestType() {
0248: }
0249:
0250: public String getName() {
0251: return name;
0252: }
0253:
0254: public void setName(String name) {
0255: this .name = name;
0256: }
0257:
0258: public String getFolder() {
0259: return folder;
0260: }
0261:
0262: public void setFolder(String folder) {
0263: this .folder = folder;
0264: }
0265:
0266: public String getRuntimeCP() {
0267: return runtimeCP;
0268: }
0269:
0270: public void setRuntimeCP(String runtimeCP) {
0271: this .runtimeCP = runtimeCP;
0272: }
0273:
0274: public String getCompileCP() {
0275: return compileCP;
0276: }
0277:
0278: public void setCompileCP(String compileCP) {
0279: this .compileCP = compileCP;
0280: }
0281:
0282: public String getCompileDep() {
0283: return compileDep;
0284: }
0285:
0286: public void setCompileDep(String compileDep) {
0287: this .compileDep = compileDep;
0288: }
0289: }
0290:
0291: List<TestType> testTypes = new LinkedList<TestType>();
0292:
0293: public void addTestType(TestType testType) {
0294: testTypes.add(testType);
0295: }
0296:
0297: public void add(TestType testType) {
0298: testTypes.add(testType);
0299: }
0300:
0301: private TestType getTestType(String name) {
0302: for (TestType testType : testTypes) {
0303: if (testType.getName().equals(name)) {
0304: return testType;
0305: }
0306: }
0307: return null;
0308: }
0309:
0310: private void define(String prop, String val) {
0311: log("Setting " + prop + "=" + val, Project.MSG_VERBOSE);
0312: String old = getProject().getProperty(prop);
0313: if (old != null && !old.equals(val)) {
0314: getProject().log(
0315: "Warning: " + prop + " was already set to " + old,
0316: Project.MSG_WARN);
0317: }
0318: getProject().setNewProperty(prop, val);
0319: }
0320:
0321: public @Override
0322: void execute() throws BuildException {
0323: try {
0324: if (getProjectFile() == null) {
0325: throw new BuildException(
0326: "You must set 'project' or 'projectfile'",
0327: getLocation());
0328: }
0329: // XXX validate against nbm-project{,2}.xsd; does this require JDK 1.5?
0330: // Cf.: ant/project/eg/ValidateAllBySchema.java
0331: // XXX share parse w/ ModuleListParser
0332: Document pDoc = XMLUtil.parse(new InputSource(
0333: getProjectFile().toURI().toString()), false, true, /*XXX*/
0334: null, null);
0335: if (publicPackagesProperty != null
0336: || javadocPackagesProperty != null) {
0337: PublicPackage[] pkgs = getPublicPackages(pDoc);
0338: if (publicPackagesProperty != null) {
0339: String val;
0340: if (pkgs.length > 0) {
0341: String sep = "";
0342: StringBuffer b = new StringBuffer();
0343: for (PublicPackage p : pkgs) {
0344: b.append(sep);
0345:
0346: String name = p.name;
0347: if (name.indexOf(',') >= 0) {
0348: throw new BuildException(
0349: "Package name cannot contain ',' as "
0350: + p, getLocation());
0351: }
0352: if (name.indexOf('*') >= 0) {
0353: throw new BuildException(
0354: "Package name cannot contain '*' as "
0355: + p, getLocation());
0356: }
0357:
0358: b.append(name);
0359: if (p.subpackages) {
0360: b.append(".**");
0361: } else {
0362: b.append(".*");
0363: }
0364: sep = ", ";
0365: }
0366: val = b.toString();
0367: } else {
0368: val = "-";
0369: }
0370: define(publicPackagesProperty, val);
0371: }
0372: NO_JAVA_DOC_PROPERTY_SET: if (javadocPackagesProperty != null) {
0373: if (pkgs.length > 0) {
0374: String sep = "";
0375: StringBuffer b = new StringBuffer();
0376: for (PublicPackage p : pkgs) {
0377: b.append(sep);
0378: if (p.subpackages) {
0379: if (getProject().getProperty(
0380: javadocPackagesProperty) == null) {
0381: String msg = javadocPackagesProperty
0382: + " cannot be set as <subpackages> does not work for Javadoc (see <subpackages>"
0383: + p.name
0384: + "</subpackages> tag in "
0385: + getProjectFile()
0386: + "). Set the property in project.properties if you want to build Javadoc.";
0387: // #52135: do not halt the build, just leave it.
0388: getProject().log("Warning: " + msg,
0389: Project.MSG_WARN);
0390: }
0391: break NO_JAVA_DOC_PROPERTY_SET;
0392: }
0393: b.append(p.name);
0394: sep = ", ";
0395: }
0396: define(javadocPackagesProperty, b.toString());
0397: }
0398: }
0399: }
0400: if (friendsProperty != null) {
0401: String[] friends = getFriends(pDoc);
0402: if (friends != null) {
0403: StringBuffer b = new StringBuffer();
0404: for (String f : friends) {
0405: if (b.length() > 0) {
0406: b.append(", ");
0407: }
0408: b.append(f);
0409: }
0410: define(friendsProperty, b.toString());
0411: }
0412: }
0413: ModuleListParser modules = null;
0414: Dep[] deps = null;
0415: if (moduleDependenciesProperty != null
0416: || moduleClassPathProperty != null
0417: || moduleRunClassPathProperty != null
0418: || testTypes.size() > 0) {
0419: @SuppressWarnings("unchecked")
0420: Hashtable<String, String> properties = getProject()
0421: .getProperties();
0422: properties.put("project", project.getAbsolutePath());
0423: modules = new ModuleListParser(properties,
0424: getModuleType(pDoc), getProject());
0425: ModuleListParser.Entry myself = modules
0426: .findByCodeNameBase(getCodeNameBase(pDoc));
0427: if (myself == null) { // #71130
0428: ModuleListParser.resetCaches();
0429: modules = new ModuleListParser(properties,
0430: getModuleType(pDoc), getProject());
0431: String cnb = getCodeNameBase(pDoc);
0432: myself = modules.findByCodeNameBase(cnb);
0433: assert myself != null : "Cannot find myself as "
0434: + cnb;
0435: }
0436: deps = getDeps(pDoc, modules);
0437: }
0438: if (moduleDependenciesProperty != null) {
0439: if (moduleDependenciesProperty != null) {
0440: StringBuffer b = new StringBuffer();
0441: for (Dep d : deps) {
0442: if (!d.run) {
0443: continue;
0444: }
0445: if (b.length() > 0) {
0446: b.append(", ");
0447: }
0448: b.append(d);
0449: }
0450: if (b.length() > 0) {
0451: define(moduleDependenciesProperty, b.toString());
0452: }
0453: }
0454: }
0455: if (codeNameBaseDashesProperty != null) {
0456: String cnb = getCodeNameBase(pDoc);
0457: define(codeNameBaseDashesProperty, cnb
0458: .replace('.', '-'));
0459: }
0460: if (codeNameBaseSlashesProperty != null) {
0461: String cnb = getCodeNameBase(pDoc);
0462: define(codeNameBaseSlashesProperty, cnb.replace('.',
0463: '/'));
0464: }
0465: if (moduleClassPathProperty != null) {
0466: String cp = computeClasspath(pDoc, modules, deps, false);
0467: define(moduleClassPathProperty, cp);
0468: }
0469: if (moduleRunClassPathProperty != null) {
0470: String cp = computeClasspath(pDoc, modules, deps, true);
0471: define(moduleRunClassPathProperty, cp);
0472: }
0473: if (domainProperty != null) {
0474: if (getModuleType(pDoc) != TYPE_NB_ORG) {
0475: throw new BuildException("Cannot set "
0476: + domainProperty
0477: + " for a non-netbeans.org module",
0478: getLocation());
0479: }
0480: File nball = new File(getProject()
0481: .getProperty("nb_all"));
0482: File basedir = getProject().getBaseDir();
0483: Pattern p = Pattern
0484: .compile("([^/]+)(/([^/]+))*//([^/]+)/"
0485: + Pattern.quote(basedir.getName()));
0486: Reader r = new FileReader(new File(nball,
0487: "nbbuild/translations"));
0488: try {
0489: BufferedReader br = new BufferedReader(r);
0490: String line;
0491: while ((line = br.readLine()) != null) {
0492: Matcher m = p.matcher(line);
0493: if (m.matches()) {
0494: define(domainProperty, m.group(1));
0495: break;
0496: }
0497: }
0498: } finally {
0499: r.close();
0500: }
0501: }
0502: if (classPathExtensionsProperty != null) {
0503: String val = computeClassPathExtensions(pDoc);
0504: if (val != null) {
0505: define(classPathExtensionsProperty, val);
0506: }
0507: }
0508:
0509: // Test dependecies
0510: //
0511: if (modules != null) {
0512: String testDistLocation = getProject().getProperty(
0513: TestDeps.TEST_DIST_VAR);
0514: if (testDistLocation == null) {
0515: testDistLocation = "${" + TestDeps.TEST_DIST_VAR
0516: + "}";
0517: }
0518: ParseProjectXml.testDistLocation = testDistLocation;
0519:
0520: for (TestDeps td : getTestDeps(pDoc, modules,
0521: getCodeNameBase(pDoc))) {
0522: // unit tests
0523: TestType testType = getTestType(td.testtype);
0524: if (testType != null) {
0525: if (testType.getFolder() != null) {
0526: define(testType.getFolder(), td
0527: .getTestFolder());
0528: }
0529: if (testType.getCompileCP() != null
0530: && td.getCompileClassPath() != null
0531: && td.getCompileClassPath().trim()
0532: .length() > 0) {
0533: define(testType.getCompileCP(), td
0534: .getCompileClassPath());
0535: }
0536: if (testType.getRuntimeCP() != null
0537: && td.getRuntimeClassPath() != null
0538: && td.getRuntimeClassPath().trim()
0539: .length() > 0) {
0540: define(testType.getRuntimeCP(), td
0541: .getRuntimeClassPath());
0542: }
0543: if (TestDeps.UNIT.equals(td.testtype)) {
0544: String testCompileDep = td
0545: .getTestCompileDep();
0546: if (testType.getCompileDep() != null
0547: && testCompileDep != null) {
0548: define(testType.getCompileDep(),
0549: testCompileDep);
0550: }
0551: }
0552: }
0553: }
0554: }
0555: } catch (BuildException e) {
0556: throw e;
0557: } catch (Exception e) {
0558: throw new BuildException(e, getLocation());
0559: }
0560: }
0561:
0562: private Element getConfig(Document pDoc) throws BuildException {
0563: Element e = pDoc.getDocumentElement();
0564: Element c = XMLUtil.findElement(e, "configuration", PROJECT_NS);
0565: if (c == null) {
0566: throw new BuildException("No <configuration>",
0567: getLocation());
0568: }
0569: Element d = findNBMElement(c, "data");
0570: if (d == null) {
0571: throw new BuildException(
0572: "No <data> in " + getProjectFile(), getLocation());
0573: }
0574: return d;
0575: }
0576:
0577: private static final class PublicPackage extends Object {
0578: public final String name;
0579: public boolean subpackages;
0580:
0581: public PublicPackage(String name, boolean subpackages) {
0582: this .name = name;
0583: this .subpackages = subpackages;
0584: }
0585: }
0586:
0587: private PublicPackage[] getPublicPackages(Document d)
0588: throws BuildException {
0589: Element cfg = getConfig(d);
0590: Element pp = findNBMElement(cfg, "public-packages");
0591: if (pp == null) {
0592: pp = findNBMElement(cfg, "friend-packages");
0593: }
0594: if (pp == null) {
0595: throw new BuildException("No <public-packages>",
0596: getLocation());
0597: }
0598: List<PublicPackage> pkgs = new ArrayList<PublicPackage>();
0599: for (Element p : XMLUtil.findSubElements(pp)) {
0600: boolean sub = false;
0601: if ("friend".equals(p.getNodeName())) {
0602: continue;
0603: }
0604: if (!"package".equals(p.getNodeName())) {
0605: if (!("subpackages".equals(p.getNodeName()))) {
0606: throw new BuildException(
0607: "Strange element name, should be package or subpackages: "
0608: + p.getNodeName(), getLocation());
0609: }
0610: sub = true;
0611: }
0612:
0613: String t = XMLUtil.findText(p);
0614: if (t == null) {
0615: throw new BuildException("No text in <package>",
0616: getLocation());
0617: }
0618: pkgs.add(new PublicPackage(t, sub));
0619: }
0620: return pkgs.toArray(new PublicPackage[pkgs.size()]);
0621: }
0622:
0623: private String[] getFriends(Document d) throws BuildException {
0624: Element cfg = getConfig(d);
0625: Element pp = findNBMElement(cfg, "friend-packages");
0626: if (pp == null) {
0627: return null;
0628: }
0629: List<String> friends = new ArrayList<String>();
0630: boolean other = false;
0631: for (Element p : XMLUtil.findSubElements(pp)) {
0632: if ("friend".equals(p.getNodeName())) {
0633: String t = XMLUtil.findText(p);
0634: if (t == null) {
0635: throw new BuildException("No text in <friend>",
0636: getLocation());
0637: }
0638: friends.add(t);
0639: } else {
0640: other = true;
0641: }
0642: }
0643: if (friends.isEmpty()) {
0644: throw new BuildException(
0645: "Must have at least one <friend> in <friend-packages>",
0646: getLocation());
0647: }
0648: if (!other) {
0649: throw new BuildException(
0650: "Must have at least one <package> in <friend-packages>",
0651: getLocation());
0652: }
0653: return friends.toArray(new String[friends.size()]);
0654: }
0655:
0656: private final class Dep {
0657: private final ModuleListParser modules;
0658: /** will be e.g. org.netbeans.modules.form */
0659: public String codenamebase;
0660: public String release = null;
0661: public String spec = null;
0662: public boolean impl = false;
0663: public boolean compile = false;
0664: public boolean run = false;
0665:
0666: public Dep(ModuleListParser modules) {
0667: this .modules = modules;
0668: }
0669:
0670: public @Override
0671: String toString() throws BuildException {
0672: StringBuffer b = new StringBuffer(codenamebase);
0673: if (release != null) {
0674: b.append('/');
0675: b.append(release);
0676: }
0677: if (spec != null) {
0678: b.append(" > ");
0679: b.append(spec);
0680: assert !impl;
0681: }
0682: if (impl) {
0683: b.append(" = "); // NO18N
0684: String implVers = implementationVersionOf(modules,
0685: codenamebase);
0686: if (implVers == null) {
0687: throw new BuildException(
0688: "No OpenIDE-Module-Implementation-Version found in "
0689: + codenamebase);
0690: }
0691: b.append(implVers);
0692: }
0693: return b.toString();
0694: }
0695:
0696: private String implementationVersionOf(
0697: ModuleListParser modules, String cnb)
0698: throws BuildException {
0699: File jar = computeClasspathModuleLocation(modules, cnb,
0700: null, null, null);
0701: if (!jar.isFile()) {
0702: throw new BuildException("No such classpath entry: "
0703: + jar, getLocation());
0704: }
0705: try {
0706: JarFile jarFile = new JarFile(jar, false);
0707: try {
0708: return jarFile
0709: .getManifest()
0710: .getMainAttributes()
0711: .getValue(
0712: "OpenIDE-Module-Implementation-Version");
0713: } finally {
0714: jarFile.close();
0715: }
0716: } catch (IOException e) {
0717: throw new BuildException(e, getLocation());
0718: }
0719: }
0720:
0721: private boolean matches(Attributes attr) {
0722: String givenCodeName = attr.getValue("OpenIDE-Module");
0723: int slash = givenCodeName.indexOf('/');
0724: int givenRelease = -1;
0725: if (slash != -1) {
0726: assert codenamebase.equals(givenCodeName.substring(0,
0727: slash));
0728: givenRelease = Integer.parseInt(givenCodeName
0729: .substring(slash + 1));
0730: }
0731: if (release != null) {
0732: int dash = release.indexOf('-');
0733: if (dash == -1) {
0734: if (Integer.parseInt(release) != givenRelease) {
0735: return false;
0736: }
0737: } else {
0738: int lower = Integer.parseInt(release.substring(0,
0739: dash));
0740: int upper = Integer.parseInt(release
0741: .substring(dash + 1));
0742: if (givenRelease < lower || givenRelease > upper) {
0743: return false;
0744: }
0745: }
0746: } else if (run && givenRelease != -1) {
0747: return false;
0748: }
0749: if (spec != null) {
0750: String givenSpec = attr
0751: .getValue("OpenIDE-Module-Specification-Version");
0752: if (givenSpec == null) {
0753: return false;
0754: }
0755: // XXX cannot use org.openide.modules.SpecificationVersion from here
0756: int[] specVals = digitize(spec);
0757: int[] givenSpecVals = digitize(givenSpec);
0758: int len1 = specVals.length;
0759: int len2 = givenSpecVals.length;
0760: int max = Math.max(len1, len2);
0761: for (int i = 0; i < max; i++) {
0762: int d1 = ((i < len1) ? specVals[i] : 0);
0763: int d2 = ((i < len2) ? givenSpecVals[i] : 0);
0764: if (d1 < d2) {
0765: break;
0766: } else if (d1 > d2) {
0767: return false;
0768: }
0769: }
0770: }
0771: if (impl) {
0772: if (attr
0773: .getValue("OpenIDE-Module-Implementation-Version") == null) {
0774: return false;
0775: }
0776: }
0777: return true;
0778: }
0779:
0780: private int[] digitize(String spec)
0781: throws NumberFormatException {
0782: StringTokenizer tok = new StringTokenizer(spec, ".");
0783: int len = tok.countTokens();
0784: int[] digits = new int[len];
0785: for (int i = 0; i < len; i++) {
0786: digits[i] = Integer.parseInt(tok.nextToken());
0787: }
0788: return digits;
0789: }
0790:
0791: }
0792:
0793: private Dep[] getDeps(Document pDoc, ModuleListParser modules)
0794: throws BuildException {
0795: Element cfg = getConfig(pDoc);
0796: Element md = findNBMElement(cfg, "module-dependencies");
0797: if (md == null) {
0798: throw new BuildException("No <module-dependencies>",
0799: getLocation());
0800: }
0801: List<Dep> deps = new ArrayList<Dep>();
0802: for (Element dep : XMLUtil.findSubElements(md)) {
0803: Dep d = new Dep(modules);
0804: Element cnb = findNBMElement(dep, "code-name-base");
0805: if (cnb == null) {
0806: throw new BuildException("No <code-name-base>",
0807: getLocation());
0808: }
0809: String t = XMLUtil.findText(cnb);
0810: if (t == null) {
0811: throw new BuildException("No text in <code-name-base>",
0812: getLocation());
0813: }
0814: d.codenamebase = t;
0815: Element rd = findNBMElement(dep, "run-dependency");
0816: if (rd != null) {
0817: d.run = true;
0818: Element rv = findNBMElement(rd, "release-version");
0819: if (rv != null) {
0820: t = XMLUtil.findText(rv);
0821: if (t == null) {
0822: throw new BuildException(
0823: "No text in <release-version>",
0824: getLocation());
0825: }
0826: d.release = t;
0827: }
0828: Element sv = findNBMElement(rd, "specification-version");
0829: if (sv != null) {
0830: t = XMLUtil.findText(sv);
0831: if (t == null) {
0832: throw new BuildException(
0833: "No text in <specification-version>",
0834: getLocation());
0835: }
0836: d.spec = t;
0837: }
0838: Element iv = findNBMElement(rd,
0839: "implementation-version");
0840: if (iv != null) {
0841: d.impl = true;
0842: }
0843: }
0844: d.compile = findNBMElement(dep, "compile-dependency") != null;
0845: deps.add(d);
0846: }
0847: return deps.toArray(new Dep[deps.size()]);
0848: }
0849:
0850: private String getCodeNameBase(Document d) throws BuildException {
0851: Element data = getConfig(d);
0852: Element name = findNBMElement(data, "code-name-base");
0853: if (name == null) {
0854: throw new BuildException("No <code-name-base>",
0855: getLocation());
0856: }
0857: String t = XMLUtil.findText(name);
0858: if (t == null) {
0859: throw new BuildException("No text in <code-name-base>",
0860: getLocation());
0861: }
0862: return t;
0863: }
0864:
0865: private int getModuleType(Document d) throws BuildException {
0866: Element data = getConfig(d);
0867: if (findNBMElement(data, "suite-component") != null) {
0868: return TYPE_SUITE;
0869: } else if (findNBMElement(data, "standalone") != null) {
0870: return TYPE_STANDALONE;
0871: } else {
0872: return TYPE_NB_ORG;
0873: }
0874: }
0875:
0876: private String computeClasspath(Document pDoc,
0877: ModuleListParser modules, Dep[] deps, boolean runtime)
0878: throws BuildException, IOException, SAXException {
0879: String myCnb = getCodeNameBase(pDoc);
0880: StringBuffer cp = new StringBuffer();
0881: String includedClustersProp = getProject().getProperty(
0882: "enabled.clusters");
0883: Set<String> includedClusters = includedClustersProp != null ? new HashSet<String>(
0884: Arrays.asList(includedClustersProp.split(" *, *")))
0885: : null;
0886: // Compatibility:
0887: String excludedClustersProp = getProject().getProperty(
0888: "disabled.clusters");
0889: Set<String> excludedClusters = excludedClustersProp != null ? new HashSet<String>(
0890: Arrays.asList(excludedClustersProp.split(" *, *")))
0891: : null;
0892: String excludedModulesProp = getProject().getProperty(
0893: "disabled.modules");
0894: Set<String> excludedModules = excludedModulesProp != null ? new HashSet<String>(
0895: Arrays.asList(excludedModulesProp.split(" *, *")))
0896: : null;
0897: for (Dep dep : deps) { // XXX should operative transitively if runtime
0898: if (!dep.compile) { // XXX should be sensitive to runtime
0899: continue;
0900: }
0901: String cnb = dep.codenamebase;
0902: File depJar = computeClasspathModuleLocation(modules, cnb,
0903: includedClusters, excludedClusters, excludedModules);
0904:
0905: Attributes attr;
0906: if (!depJar.isFile()) {
0907: throw new BuildException("No such classpath entry: "
0908: + depJar, getLocation());
0909: }
0910: JarFile jarFile = new JarFile(depJar, false);
0911: try {
0912: attr = jarFile.getManifest().getMainAttributes();
0913: } finally {
0914: jarFile.close();
0915: }
0916:
0917: if (!dep.matches(attr)) { // #68631
0918: throw new BuildException(
0919: "Cannot compile against a module: " + depJar
0920: + " because of dependency: " + dep,
0921: getLocation());
0922: }
0923:
0924: if (!runtime
0925: && Boolean.parseBoolean(attr
0926: .getValue("OpenIDE-Module-Deprecated"))) {
0927: log("The module " + cnb + " has been deprecated",
0928: Project.MSG_WARN);
0929: }
0930:
0931: List<File> additions = new ArrayList<File>();
0932: additions.add(depJar);
0933: if (runtime) {
0934: Set<String> skipCnb = new HashSet<String>();
0935: addRecursiveDeps(additions, modules, cnb,
0936: includedClusters, excludedClusters,
0937: excludedModules, skipCnb);
0938: }
0939:
0940: // #52354: look for <class-path-extension>s in dependent modules.
0941: ModuleListParser.Entry entry = modules
0942: .findByCodeNameBase(cnb);
0943: if (entry != null) {
0944: additions.addAll(Arrays.asList(entry
0945: .getClassPathExtensions()));
0946: }
0947:
0948: if (!dep.impl && /* #71807 */dep.run) {
0949: String friends = attr
0950: .getValue("OpenIDE-Module-Friends");
0951: if (friends != null
0952: && !Arrays.asList(friends.split(" *, *"))
0953: .contains(myCnb)) {
0954: throw new BuildException("The module " + myCnb
0955: + " is not a friend of " + depJar,
0956: getLocation());
0957: }
0958: String pubpkgs = attr
0959: .getValue("OpenIDE-Module-Public-Packages");
0960: if ("-".equals(pubpkgs)) {
0961: throw new BuildException(
0962: "The module "
0963: + depJar
0964: + " has no public packages and so cannot be compiled against",
0965: getLocation());
0966: } else if (pubpkgs != null && !runtime
0967: && publicPackageJarDir != null) {
0968: File splitJar = createPublicPackageJar(additions,
0969: pubpkgs, publicPackageJarDir, cnb);
0970: additions.clear();
0971: additions.add(splitJar);
0972: }
0973: }
0974:
0975: for (File f : additions) {
0976: if (cp.length() > 0) {
0977: cp.append(':');
0978: }
0979: cp.append(f.getAbsolutePath());
0980: }
0981: }
0982: // Also look for <class-path-extension>s for myself and put them in my own classpath.
0983: ModuleListParser.Entry entry = modules
0984: .findByCodeNameBase(myCnb);
0985: if (entry == null) {
0986: throw new IllegalStateException("Cannot find myself as "
0987: + myCnb);
0988: }
0989: for (File f : entry.getClassPathExtensions()) {
0990: cp.append(':');
0991: cp.append(f.getAbsolutePath());
0992: }
0993: return cp.toString();
0994: }
0995:
0996: private void addRecursiveDeps(List<File> additions,
0997: ModuleListParser modules, String cnb,
0998: Set<String> includedClusters, Set<String> excludedClusters,
0999: Set<String> excludedModules, Set<String> skipCnb) {
1000: if (!skipCnb.add(cnb)) {
1001: return;
1002: }
1003: log("Processing for recursive deps: " + cnb,
1004: Project.MSG_VERBOSE); // NO18N
1005: for (String nextModule : modules.findByCodeNameBase(cnb)
1006: .getRuntimeDependencies()) {
1007: log(" Added dep: " + nextModule, Project.MSG_VERBOSE); // NO18N
1008: File depJar = computeClasspathModuleLocation(modules,
1009: nextModule, includedClusters, excludedClusters,
1010: excludedModules);
1011:
1012: if (!depJar.isFile()) {
1013: log("No such classpath entry: " + depJar,
1014: Project.MSG_WARN);
1015: }
1016:
1017: if (!additions.contains(depJar)) {
1018: additions.add(depJar);
1019: }
1020:
1021: ModuleListParser.Entry entry = modules
1022: .findByCodeNameBase(cnb);
1023: if (entry != null) {
1024: for (File f : entry.getClassPathExtensions()) {
1025: if (!additions.contains(f)) {
1026: additions.add(f);
1027: }
1028: }
1029: }
1030:
1031: addRecursiveDeps(additions, modules, nextModule,
1032: includedClusters, excludedClusters,
1033: excludedModules, skipCnb);
1034: }
1035: }
1036:
1037: private File computeClasspathModuleLocation(
1038: ModuleListParser modules, String cnb,
1039: Set<String> includedClusters, Set<String> excludedClusters,
1040: Set<String> excludedModules) throws BuildException {
1041: ModuleListParser.Entry module = modules.findByCodeNameBase(cnb);
1042: if (module == null) {
1043: throw new BuildException("No dependent module " + cnb,
1044: getLocation());
1045: }
1046: String cluster = module.getClusterName();
1047: if (cluster != null) { // #68716
1048: if ((includedClusters != null
1049: && !includedClusters.isEmpty() && !includedClusters
1050: .contains(cluster))
1051: || ((includedClusters == null || includedClusters
1052: .isEmpty())
1053: && excludedClusters != null && excludedClusters
1054: .contains(cluster))) {
1055: throw new BuildException(
1056: "The module "
1057: + cnb
1058: + " cannot be compiled against because it is part of the cluster "
1059: + cluster
1060: + " which has been excluded from the target platform in your suite configuration",
1061: getLocation());
1062: }
1063: if (excludedModules != null
1064: && excludedModules.contains(cnb)) { // again #68716
1065: throw new BuildException("Module " + cnb
1066: + " excluded from the target platform",
1067: getLocation());
1068: }
1069: }
1070: return module.getJar();
1071: }
1072:
1073: final class TestDeps {
1074: public static final String UNIT = "unit";
1075: public static final String QA_FUNCTIONAL = "qa-functional";
1076: // unit, qa-functional, performance
1077: final String testtype;
1078: // all dependecies for the testtype
1079: final List<TestDep> dependencies = new ArrayList<TestDep>();
1080: // code name base of tested module
1081: final String cnb;
1082: final ModuleListParser modulesParser;
1083:
1084: private Set<String> missingEntries;
1085:
1086: public static final String TEST_DIST_VAR = "test.dist.dir";
1087:
1088: public TestDeps(String testtype, String cnb,
1089: ModuleListParser modulesParser) {
1090: assert modulesParser != null;
1091: this .testtype = testtype;
1092: this .cnb = cnb;
1093: this .modulesParser = modulesParser;
1094: }
1095:
1096: public List<String> getFiles(boolean compile) {
1097: List<String> files = new ArrayList<String>();
1098: for (TestDep d : dependencies) {
1099: files.addAll(d.getFiles(compile));
1100: }
1101: return files;
1102: }
1103:
1104: public void addDepenency(TestDep dep) {
1105: dependencies.add(dep);
1106: }
1107:
1108: private String getTestFolder() {
1109: ModuleListParser.Entry entry = modulesParser
1110: .findByCodeNameBase(cnb);
1111: String sep = "/";
1112:
1113: String cluster = entry.getClusterName();
1114: if (cluster == null) {
1115: // no cluster name is specified for standalone or module in module suite
1116: cluster = "cluster";
1117: }
1118: return ParseProjectXml.testDistLocation + sep + testtype
1119: + sep + cluster + sep + cnb.replace('.', '-');
1120: }
1121:
1122: String getCompileClassPath() {
1123: return getPath(getFiles(true)) + getMissingEntries();
1124: }
1125:
1126: private String getPath(List<String> files) {
1127: StringBuffer path = new StringBuffer();
1128: Set<String> filesSet = new HashSet<String>();
1129: for (String filePath : files) {
1130: if (!filesSet.contains(filePath)) {
1131: if (path.length() > 0) {
1132: path.append(File.pathSeparatorChar);
1133: }
1134: filesSet.add(filePath);
1135: path.append(filePath);
1136: }
1137: }
1138: return path.toString().replace(File.separatorChar, '/');
1139: }
1140:
1141: String getRuntimeClassPath() {
1142: return getPath(getFiles(false)) + getMissingEntries();
1143: }
1144:
1145: /** construct test compilation compilation dependencies.
1146: * Use case: unit tests of masterfs depends on tests of fs
1147: * @return relative project folder paths separated by comma
1148: */
1149: public String getTestCompileDep() {
1150: Set<String> cnbs = new HashSet<String>();
1151: StringBuilder builder = new StringBuilder();
1152: computeCompileDep(cnb, cnbs, builder);
1153: return (builder.length() > 0) ? builder.toString() : null;
1154: }
1155:
1156: private void computeCompileDep(String cnb, Set<String> cnbs,
1157: StringBuilder sb) {
1158: if (cnbs.contains(cnb)) {
1159: return;
1160: }
1161: ModuleListParser.Entry entry = modulesParser
1162: .findByCodeNameBase(cnb);
1163: if (!cnbs.isEmpty() && entry != null) {
1164: // check if is tests are already built
1165: for (TestDep td : dependencies) {
1166: if (cnb.equals(td.cnb)
1167: && new File(td.getTestJarPath()).exists()) {
1168: // don't compile already compiled tests dependencies
1169: return;
1170: }
1171: }
1172: if (sb.length() > 0) {
1173: sb.append(","); // NOI18N
1174: }
1175: // XXX it works only for netbeans.org modules :(
1176: String nborgPath = entry.getNetbeansOrgPath();
1177: if (nborgPath != null) {
1178: sb.append(nborgPath);
1179: }
1180: }
1181: cnbs.add(cnb);
1182: if (entry != null) {
1183: String testDeps[] = entry.getTestDependencies();
1184: if (testDeps != null) {
1185: for (String cnb2 : testDeps) {
1186: computeCompileDep(cnb2, cnbs, sb);
1187: }
1188: }
1189: }
1190: }
1191:
1192: public void addMisingEntry(String cnd) {
1193: if (missingEntries == null) {
1194: missingEntries = new HashSet<String>();
1195: }
1196: missingEntries.add(cnd);
1197: }
1198:
1199: public String getMissingEntries() {
1200: if (missingEntries != null) {
1201: StringBuilder builder = new StringBuilder();
1202: builder.append("\n-missing-Module-Entries-: ");
1203: for (String cnd : missingEntries) {
1204: builder.append(cnd);
1205: builder.append("\n");
1206: }
1207: return builder.toString();
1208: }
1209: return "";
1210: }
1211: }
1212:
1213: /** Test dependency for module and type
1214: */
1215: final class TestDep {
1216: final ModuleListParser modulesParser;
1217: // code name base
1218: final String cnb;
1219: // dependencies on tests of modules
1220: final boolean recursive;
1221: final boolean test;
1222: // runtime classpath
1223: final boolean compile;
1224: TestDeps testDeps;
1225:
1226: TestDep(String cnb, ModuleListParser modules,
1227: boolean recursive, boolean test, boolean compile,
1228: TestDeps testDeps) {
1229: this .modulesParser = modules;
1230: this .cnb = cnb;
1231: this .recursive = recursive;
1232: this .test = test;
1233: this .testDeps = testDeps;
1234: this .compile = compile;
1235: }
1236:
1237: /* get modules dependecies
1238: */
1239: List<ModuleListParser.Entry> getModules() {
1240: List<ModuleListParser.Entry> entries = new ArrayList<ModuleListParser.Entry>();
1241: if (recursive) {
1242: Map<String, ModuleListParser.Entry> entriesMap = new HashMap<String, ModuleListParser.Entry>();
1243: addRecursiveModules(cnb, entriesMap);
1244: entries.addAll(entriesMap.values());
1245: } else {
1246: ModuleListParser.Entry entry = modulesParser
1247: .findByCodeNameBase(cnb);
1248: if (entry == null) {
1249: //throw new BuildException("Module " + cnb + " doesn't exist.");
1250: testDeps.addMisingEntry(cnb);
1251: } else {
1252: entries.add(modulesParser.findByCodeNameBase(cnb));
1253: }
1254: }
1255: return entries;
1256:
1257: }
1258:
1259: private void addRecursiveModules(String cnd,
1260: Map<String, ModuleListParser.Entry> entriesMap) {
1261: if (!entriesMap.containsKey(cnd)) {
1262: ModuleListParser.Entry entry = modulesParser
1263: .findByCodeNameBase(cnd);
1264: if (entry == null) {
1265: // throw new BuildException("Module " + cnd + " doesn't exist.");
1266: testDeps.addMisingEntry(cnd);
1267: } else {
1268: entriesMap.put(cnd, entry);
1269: String cnds[] = entry.getRuntimeDependencies();
1270: // cnds can be null
1271: if (cnds != null) {
1272: for (String c : cnds) {
1273: addRecursiveModules(c, entriesMap);
1274: }
1275: }
1276: }
1277: }
1278: }
1279:
1280: List<String> getFiles(boolean compile) {
1281: List<String> files = new ArrayList<String>();
1282: if (!compile || (compile && this .compile)) {
1283: List<ModuleListParser.Entry> modules = getModules();
1284: for (ModuleListParser.Entry entry : getModules()) {
1285: if (entry != null) {
1286: files.add(entry.getJar().getAbsolutePath());
1287: } else {
1288: log("Entry doesn't exist.");
1289: }
1290: }
1291: // get tests files
1292: if (test) {
1293: // get test folder
1294: String jarPath = getTestJarPath();
1295: if (jarPath != null) {
1296: files.add(jarPath);
1297: }
1298: }
1299: }
1300: return files;
1301: }
1302:
1303: public String getTestJarPath() {
1304: String sep = File.separator;
1305: ModuleListParser.Entry entry = modulesParser
1306: .findByCodeNameBase(cnb);
1307: if (entry == null) {
1308: testDeps.addMisingEntry(cnb);
1309: return null;
1310: } else {
1311: String cluster = entry.getClusterName();
1312: if (cluster == null) {
1313: cluster = "cluster";
1314: }
1315: return ParseProjectXml.testDistLocation + sep
1316: + testDeps.testtype + sep + cluster + sep
1317: + cnb.replace('.', '-') + sep + "tests.jar";
1318: }
1319: }
1320: }
1321:
1322: private String computeClassPathExtensions(Document pDoc) {
1323: Element data = getConfig(pDoc);
1324: StringBuffer list = null;
1325: for (Element ext : XMLUtil.findSubElements(data)) {
1326: if (!ext.getLocalName().equals("class-path-extension")) {
1327: continue;
1328: }
1329: Element runtimeRelativePath = findNBMElement(ext,
1330: "runtime-relative-path");
1331: if (runtimeRelativePath == null) {
1332: throw new BuildException(
1333: "Have malformed <class-path-extension> in "
1334: + getProjectFile(), getLocation());
1335: }
1336: String reltext = XMLUtil.findText(runtimeRelativePath);
1337: if (list == null) {
1338: list = new StringBuffer();
1339: } else {
1340: list.append(' ');
1341: }
1342: list.append(reltext);
1343: }
1344: return list != null ? list.toString() : null;
1345: }
1346:
1347: /**
1348: * Create a compact JAR containing only classes in public packages.
1349: * Forces the compiler to honor public package restrictions.
1350: * @see "#59792"
1351: */
1352: private File createPublicPackageJar(List<File> jars,
1353: String pubpkgs, File dir, String cnb) throws IOException {
1354: if (!dir.isDirectory()) {
1355: throw new IOException("No such directory " + dir);
1356: }
1357: File ppjar = new File(dir, cnb.replace('.', '-') + ".jar");
1358: if (ppjar.exists()) {
1359: // Check if it is up to date first. Must be as new as any input JAR.
1360: boolean uptodate = true;
1361: long stamp = ppjar.lastModified();
1362: for (File jar : jars) {
1363: if (jar.lastModified() > stamp) {
1364: uptodate = false;
1365: break;
1366: }
1367: }
1368: if (uptodate) {
1369: log("Distilled " + ppjar + " was already up to date",
1370: Project.MSG_VERBOSE);
1371: return ppjar;
1372: }
1373: }
1374: log("Distilling " + ppjar + " from " + jars);
1375: String corePattern = pubpkgs.replaceAll(" +", "").replaceAll(
1376: "\\.", "/").replaceAll(",", "|").replaceAll("\\*\\*",
1377: "(.+/)?").replaceAll("\\*", "");
1378: Pattern p = Pattern.compile("(" + corePattern
1379: + ")[^/]+\\.class");
1380: // E.g.: (org/netbeans/api/foo/|org/netbeans/spi/foo/)[^/]+\.class
1381: OutputStream os = new FileOutputStream(ppjar);
1382: try {
1383: ZipOutputStream zos = new ZipOutputStream(os);
1384: Set<String> addedPaths = new HashSet<String>();
1385: for (File jar : jars) {
1386: if (!jar.isFile()) {
1387: log("Classpath entry " + jar
1388: + " does not exist; skipping",
1389: Project.MSG_WARN);
1390: }
1391: InputStream is = new FileInputStream(jar);
1392: try {
1393: ZipInputStream zis = new ZipInputStream(is);
1394: ZipEntry inEntry;
1395: while ((inEntry = zis.getNextEntry()) != null) {
1396: String path = inEntry.getName();
1397: if (!addedPaths.add(path)) {
1398: continue;
1399: }
1400: if (!p.matcher(path).matches()) {
1401: continue;
1402: }
1403: ByteArrayOutputStream baos = new ByteArrayOutputStream();
1404: byte[] buf = new byte[4096];
1405: int read;
1406: while ((read = zis.read(buf)) != -1) {
1407: baos.write(buf, 0, read);
1408: }
1409: byte[] data = baos.toByteArray();
1410: ZipEntry outEntry = new ZipEntry(path);
1411: outEntry.setSize(data.length);
1412: CRC32 crc = new CRC32();
1413: crc.update(data);
1414: outEntry.setCrc(crc.getValue());
1415: zos.putNextEntry(outEntry);
1416: zos.write(data);
1417: }
1418: } finally {
1419: is.close();
1420: }
1421: }
1422: zos.close();
1423: } finally {
1424: os.close();
1425: }
1426: return ppjar;
1427: }
1428:
1429: private TestDeps[] getTestDeps(Document pDoc,
1430: ModuleListParser modules, String testCnb) {
1431: assert modules != null;
1432: Element cfg = getConfig(pDoc);
1433: List<TestDeps> testDepsList = new ArrayList<TestDeps>();
1434: Element pp = findNBMElement(cfg, "test-dependencies");
1435: boolean existsUnitTests = false;
1436: boolean existsQaFunctionalTests = false;
1437: if (pp != null) {
1438: for (Element depssEl : XMLUtil.findSubElements(pp)) {
1439: String testType = findTextOrNull(depssEl, "name");
1440: if (testType == null) {
1441: testType = TestDeps.UNIT; // default variant
1442: existsUnitTests = true;
1443: } else if (testType.equals(TestDeps.UNIT)) {
1444: existsUnitTests = true;
1445: } else if (testType.equals(TestDeps.QA_FUNCTIONAL)) {
1446: existsQaFunctionalTests = true;
1447: }
1448: TestDeps testDeps = new TestDeps(testType, testCnb,
1449: modules);
1450: testDepsList.add(testDeps);
1451: for (Element el : XMLUtil.findSubElements(depssEl)) {
1452: if (el.getTagName().equals("test-dependency")) {
1453: // parse test dep
1454: boolean test = (findNBMElement(el, "test") != null);
1455: String cnb = findTextOrNull(el,
1456: "code-name-base");
1457: boolean recursive = (findNBMElement(el,
1458: "recursive") != null);
1459: boolean compile = (findNBMElement(el,
1460: "compile-dependency") != null);
1461: testDeps.addDepenency(new TestDep(cnb, modules,
1462: recursive, test, compile, testDeps));
1463: }
1464:
1465: }
1466:
1467: }
1468: }
1469: // #82204 intialize default testtypes when are not in project.xml
1470: if (!existsUnitTests) {
1471: log("Default TestDeps for unit", Project.MSG_VERBOSE);
1472: testDepsList.add(new TestDeps(TestDeps.UNIT, testCnb,
1473: modules));
1474: }
1475: if (!existsQaFunctionalTests) {
1476: log("Default TestDeps for qa-functional",
1477: Project.MSG_VERBOSE);
1478: testDepsList.add(new TestDeps(TestDeps.QA_FUNCTIONAL,
1479: testCnb, modules));
1480: }
1481: return testDepsList.toArray(new TestDeps[testDepsList.size()]);
1482: }
1483:
1484: static String findTextOrNull(Element parentElement,
1485: String elementName) {
1486: Element el = findNBMElement(parentElement, elementName);
1487: return (el == null) ? null : XMLUtil.findText(el);
1488:
1489: }
1490:
1491: private static String NBM_NS_CACHE = NBM_NS3;
1492:
1493: static Element findNBMElement(Element el, String name) {
1494: Element retEl = XMLUtil.findElement(el, name, NBM_NS_CACHE);
1495: if (retEl == null) {
1496: NBM_NS_CACHE = (NBM_NS_CACHE == NBM_NS3) ? NBM_NS2
1497: : NBM_NS3;
1498: retEl = XMLUtil.findElement(el, name, NBM_NS_CACHE);
1499: }
1500: return retEl;
1501: }
1502:
1503: }
|