001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.nbbuild;
043:
044: import java.io.File;
045: import java.io.IOException;
046: import java.util.HashMap;
047: import java.util.HashSet;
048: import java.util.Map;
049: import java.util.Set;
050: import java.util.StringTokenizer;
051: import java.util.jar.JarFile;
052: import java.util.jar.Manifest;
053: import javax.xml.parsers.ParserConfigurationException;
054: import javax.xml.parsers.SAXParser;
055: import javax.xml.parsers.SAXParserFactory;
056: import org.apache.tools.ant.BuildException;
057: import org.apache.tools.ant.Project;
058: import org.apache.tools.ant.types.Parameter;
059: import org.apache.tools.ant.types.selectors.BaseExtendSelector;
060: import org.xml.sax.Attributes;
061: import org.xml.sax.SAXException;
062: import org.xml.sax.helpers.DefaultHandler;
063:
064: /** Selector that accepts modules based on their code base name.
065: *
066: * @author Jaroslav Tulach
067: */
068: public final class ModuleSelector extends BaseExtendSelector {
069: private Set<String> excludeModules;
070: private Set<String> includeClusters;
071: private Set<String> excludeClusters;
072: private Map<String, String> fileToOwningModule;
073: private boolean acceptExcluded;
074:
075: /** Creates a new instance of ModuleSelector */
076: public ModuleSelector() {
077: }
078:
079: public boolean isSelected(File dir, String filename, File file)
080: throws BuildException {
081: validate();
082:
083: Boolean check = checkSelected(dir, filename, file);
084: if (check == null) {
085: return false;
086: }
087:
088: if (acceptExcluded) {
089: log("Reverting the accepted state", Project.MSG_VERBOSE);
090: return !check.booleanValue();
091: } else {
092: return check.booleanValue();
093: }
094: }
095:
096: private Boolean checkSelected(File dir, String filename, File file)
097: throws BuildException {
098: if (file.isDirectory()) {
099: log("Skipping directory: " + file, Project.MSG_VERBOSE);
100: return null;
101: }
102:
103: String module = null;
104: if (file.getName().endsWith(".jar")) {
105: try {
106: JarFile jar = new JarFile(file);
107: Manifest m = jar.getManifest();
108: if (m != null) {
109: module = m.getMainAttributes().getValue(
110: "OpenIDE-Module");
111: }
112: jar.close();
113: } catch (IOException ex) {
114: throw new BuildException("Problem with file: " + file,
115: ex);
116: }
117: }
118:
119: String name = file.getName();
120: File p = file.getParentFile();
121: for (;;) {
122:
123: if (new File(p, "update_tracking").isDirectory()) { // else includeClusters does not work
124: String cluster = p.getName();
125:
126: if (!includeClusters.isEmpty()
127: && !includeClusters.contains(cluster)) {
128: log("Not included cluster: " + cluster + " for "
129: + file, Project.MSG_VERBOSE);
130: return null;
131: }
132:
133: if (includeClusters.isEmpty()
134: && excludeClusters.contains(cluster)) {
135: log(
136: "Excluded cluster: " + cluster + " for "
137: + file, Project.MSG_VERBOSE);
138: return null;
139: }
140: }
141:
142: if (module == null && fileToOwningModule != null) {
143: module = fileToOwningModule.get(name);
144: }
145:
146: if (dir.equals(p)) {
147: break;
148: }
149: name = p.getName() + '/' + name;
150: p = p.getParentFile();
151: }
152:
153: if (module == null) {
154: log("No module in: " + file, Project.MSG_VERBOSE);
155: return null;
156: }
157: int slash = module.indexOf('/');
158: if (slash >= 0) {
159: module = module.substring(0, slash);
160: }
161:
162: if (excludeModules.contains(module)) {
163: log("Excluded module: " + file, Project.MSG_VERBOSE);
164: return Boolean.FALSE;
165: }
166:
167: log("Accepted file: " + file, Project.MSG_VERBOSE);
168: return Boolean.TRUE;
169: }
170:
171: public void verifySettings() {
172: if (includeClusters != null) {
173: return;
174: }
175:
176: includeClusters = new HashSet<String>();
177: excludeClusters = new HashSet<String>();
178: excludeModules = new HashSet<String>();
179:
180: Parameter[] arr = getParameters();
181: if (arr == null) {
182: return;
183: }
184:
185: for (Parameter p : arr) {
186: if ("excludeModules".equals(p.getName())) {
187: parse(p.getValue(), excludeModules);
188: log("Will excludeModules: " + excludeModules,
189: Project.MSG_VERBOSE);
190: continue;
191: }
192: if ("includeClusters".equals(p.getName())) {
193: parse(p.getValue(), includeClusters);
194: log("Will includeClusters: " + includeClusters,
195: Project.MSG_VERBOSE);
196: continue;
197: }
198: if ("excludeClusters".equals(p.getName())) {
199: parse(p.getValue(), excludeClusters);
200: log("Will excludeClusters: " + excludeClusters,
201: Project.MSG_VERBOSE);
202: continue;
203: }
204: if ("excluded".equals(p.getName())) {
205: acceptExcluded = Boolean.parseBoolean(p.getValue());
206: log("Will acceptExcluded: " + acceptExcluded,
207: Project.MSG_VERBOSE);
208: continue;
209: }
210: if ("updateTrackingFiles".equals(p.getName())) {
211: fileToOwningModule = new HashMap<String, String>();
212: try {
213: readUpdateTracking(getProject(), p.getValue(),
214: fileToOwningModule);
215: } catch (IOException ex) {
216: throw new BuildException(ex);
217: } catch (ParserConfigurationException ex) {
218: throw new BuildException(ex);
219: } catch (SAXException ex) {
220: throw new BuildException(ex);
221: }
222: log("Will accept these files: "
223: + fileToOwningModule.keySet(),
224: Project.MSG_VERBOSE);
225: continue;
226: }
227: setError("Unknown parameter: " + p.getName());
228: }
229: }
230:
231: private static void parse(String tokens, Set<String> to) {
232: StringTokenizer tok = new StringTokenizer(tokens, ", \n");
233:
234: while (tok.hasMoreElements()) {
235: to.add(tok.nextToken());
236: }
237: }
238:
239: static void readUpdateTracking(final Project p, String tokens,
240: final Map<String, String> files) throws SAXException,
241: IOException, ParserConfigurationException {
242: StringTokenizer tok = new StringTokenizer(tokens,
243: File.pathSeparator);
244:
245: SAXParserFactory factory = SAXParserFactory.newInstance();
246: factory.setValidating(false);
247: final SAXParser parser = factory.newSAXParser();
248:
249: class MyHandler extends DefaultHandler {
250: public File where;
251: public String module;
252:
253: public void startElement(String uri, String localName,
254: String qName, Attributes attributes)
255: throws SAXException {
256: if (qName.equals("file")) {
257: String file = attributes.getValue("name");
258: if (file == null) {
259: throw new BuildException(
260: "<file/> without name attribute in "
261: + where);
262: }
263:
264: files.put(file.replace(File.separatorChar, '/'),
265: module);
266: }
267: }
268:
269: public void iterate(StringTokenizer tok)
270: throws SAXException, IOException {
271: while (tok.hasMoreElements()) {
272: where = new File(tok.nextToken());
273:
274: module = where.getName();
275: if (module.endsWith(".xml")) {
276: module = module.substring(0,
277: module.length() - 4);
278: }
279: module = module.replace('-', '.');
280:
281: try {
282: if (p != null) {
283: p.log("Parsing " + where,
284: Project.MSG_VERBOSE);
285: }
286: parser.parse(where, this );
287: } catch (SAXException ex) {
288: throw new BuildException("Wrong file " + where,
289: ex);
290: }
291:
292: // the update tracking file belongs to the moduel as well
293: files.put(where.getParentFile().getName() + '/'
294: + where.getName(), module);
295: }
296: }
297: }
298: MyHandler handler = new MyHandler();
299: handler.iterate(tok);
300:
301: }
302: }
|