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.*;
045: import java.util.*;
046: import java.io.FileOutputStream;
047:
048: import org.w3c.dom.*;
049: import org.xml.sax.InputSource;
050:
051: import org.apache.tools.ant.BuildException;
052: import org.xml.sax.ErrorHandler;
053: import org.xml.sax.SAXParseException;
054:
055: /** This class represents module updates tracking
056: *
057: * @author akemr
058: */
059: class UpdateTracking {
060: private static final String ELEMENT_MODULE = "module"; // NOI18N
061: private static final String ATTR_CODENAME = "codename"; // NOI18N
062: private static final String ELEMENT_VERSION = "module_version"; // NOI18N
063: private static final String ATTR_VERSION = "specification_version"; // NOI18N
064: private static final String ATTR_ORIGIN = "origin"; // NOI18N
065: private static final String ATTR_LAST = "last"; // NOI18N
066: private static final String ATTR_INSTALL = "install_time"; // NOI18N
067: private static final String ELEMENT_FILE = "file"; // NOI18N
068: private static final String ATTR_FILE_NAME = "name"; // NOI18N
069: private static final String ATTR_CRC = "crc"; // NOI18N
070:
071: private static final String NBM_ORIGIN = "nbm"; // NOI18N
072: private static final String INST_ORIGIN = "installer"; // NOI18N
073:
074: /** Platform dependent file name separator */
075: private static final String FILE_SEPARATOR = System
076: .getProperty("file.separator"); // NOI18N
077:
078: /** The name of the install_later file */
079: public static final String TRACKING_DIRECTORY = "update_tracking"; // NOI18N
080:
081: private boolean pError = false;
082:
083: private File trackingFile = null;
084:
085: private String origin = NBM_ORIGIN;
086: private String nbPath = null;
087: private Module module = null;
088: protected InputStream is = null;
089: protected OutputStream os = null;
090:
091: // for generating xml in build process
092: public UpdateTracking(String nbPath) {
093: this .nbPath = nbPath;
094: origin = INST_ORIGIN;
095: }
096:
097: /**
098: * Use this constructor, only when you want to use I/O Streams
099: */
100: public UpdateTracking() {
101: this .nbPath = null;
102: origin = INST_ORIGIN;
103: }
104:
105: public Version addNewModuleVersion(String codename,
106: String spec_version) {
107: module = new Module();
108: module.setCodename(codename);
109: Version version = new Version();
110: version.setVersion(spec_version);
111: version.setOrigin(origin);
112: version.setLast(true);
113: version.setInstall_time(System.currentTimeMillis());
114: module.setVersion(version);
115: return version;
116: }
117:
118: public String getVersionFromFile(File utf) throws BuildException {
119: this .setTrackingFile(utf.getParentFile(), utf.getName());
120: read();
121: if (module.getVersions().size() != 1)
122: throw new BuildException(
123: "Module described in update tracking file "
124: + utf.getAbsolutePath()
125: + " has got "
126: + module.getVersions().size()
127: + " specification versions. Correct number is 1.");
128: return module.getVersions().get(0).getVersion();
129: }
130:
131: public String getCodenameFromFile(File utf) throws BuildException {
132: this .setTrackingFile(utf.getParentFile(), utf.getName());
133: read();
134: if (module.getVersions().size() != 1)
135: throw new BuildException(
136: "Module described in update tracking file "
137: + utf.getAbsolutePath()
138: + " has got "
139: + module.getVersions().size()
140: + " specification versions. Correct number is 1.");
141: return module.getCodename();
142: }
143:
144: public String getVersionForCodeName(String codeName)
145: throws BuildException {
146: module = new Module();
147: module.setCodename(codeName);
148: // if (this.is == null) {
149: File directory = new File(nbPath + FILE_SEPARATOR
150: + TRACKING_DIRECTORY);
151: setTrackingFile(directory, getTrackingFileName());
152: if (!trackingFile.exists() || !trackingFile.isFile())
153: throw new BuildException("Tracking file "
154: + trackingFile.getAbsolutePath()
155: + " cannot be found for module "
156: + module.getCodenamebase());
157: // }
158: read();
159: if (module.getVersions().size() != 1)
160: throw new BuildException("Module with codenamebase "
161: + codeName + " has got "
162: + module.getVersions().size()
163: + " specification versions. Correct number is 1.");
164: return module.getVersions().get(0).getVersion();
165: }
166:
167: public String[] getListOfNBM(String codeName) throws BuildException {
168: module = new Module();
169: module.setCodename(codeName);
170: if (this .is == null) {
171: File directory = new File(nbPath + FILE_SEPARATOR
172: + TRACKING_DIRECTORY);
173: setTrackingFile(directory, getTrackingFileName());
174: if (!trackingFile.exists() || !trackingFile.isFile())
175: throw new BuildException("Tracking file "
176: + trackingFile.getAbsolutePath()
177: + " cannot be found for module "
178: + module.getCodenamebase());
179: }
180:
181: read();
182:
183: if (module.getVersions().size() != 1)
184: throw new BuildException("Module with codenamebase "
185: + codeName + " has got "
186: + module.getVersions().size()
187: + " specification versions. Correct number is 1.");
188:
189: List<ModuleFile> files = module.getVersions().get(0).getFiles();
190: String[] listFiles = new String[files.size()];
191: for (int i = 0; i < files.size(); i++) {
192: listFiles[i] = files.get(i).getName().replace(
193: File.separatorChar, '/');
194: }
195:
196: return listFiles;
197: }
198:
199: public void removeLocalized(String locale) {
200: File updateDirectory = new File(nbPath, TRACKING_DIRECTORY);
201: File[] trackingFiles = updateDirectory
202: .listFiles(new FileFilter() { // Get only *.xml files
203: public boolean accept(File file) {
204: return file.isFile()
205: && file.getName().endsWith(".xml"); //NOI18N
206: }
207: });
208: if (trackingFiles != null)
209: for (int i = trackingFiles.length - 1; i >= 0; i--) {
210: trackingFile = trackingFiles[i];
211: read();
212: module.removeLocalized(locale);
213: write();
214: }
215: }
216:
217: void write() throws BuildException {
218: Document document = XMLUtil.createDocument(ELEMENT_MODULE);
219: Element e_module = document.getDocumentElement();
220: e_module.setAttribute(ATTR_CODENAME, module.getCodename());
221: for (Version ver : module.getVersions()) {
222: Element e_version = document.createElement(ELEMENT_VERSION);
223: e_version.setAttribute(ATTR_VERSION, ver.getVersion());
224: e_version.setAttribute(ATTR_ORIGIN, ver.getOrigin());
225: e_version.setAttribute(ATTR_LAST, "true"); //NOI18N
226: e_version.setAttribute(ATTR_INSTALL, Long.toString(ver
227: .getInstall_time()));
228: e_module.appendChild(e_version);
229: for (ModuleFile file : ver.getFiles()) {
230: Element e_file = document.createElement(ELEMENT_FILE);
231: e_file.setAttribute(ATTR_FILE_NAME, file.getName()
232: .replace(File.separatorChar, '/'));
233: e_file.setAttribute(ATTR_CRC, file.getCrc());
234: e_version.appendChild(e_file);
235: }
236: }
237:
238: //document.getDocumentElement().normalize();
239: if (this .os == null) {
240: File directory = new File(nbPath + FILE_SEPARATOR
241: + TRACKING_DIRECTORY);
242: if (!directory.exists()) {
243: directory.mkdirs();
244: }
245: setTrackingFile(directory, this .getTrackingFileName());
246: FileOutputStream fos = null;
247: try {
248: fos = new FileOutputStream(new File(directory, this
249: .getTrackingFileName()));
250: } catch (Exception e) {
251: throw new BuildException(
252: "Could not get outputstream to write update tracking",
253: e);
254: }
255: this .setTrackingOutputStream(fos);
256: }
257: try {
258: try {
259: XMLUtil.write(document, this .os);
260: } finally {
261: this .os.close();
262: }
263: } catch (Exception e) {
264: e.printStackTrace();
265: if ((trackingFile != null) && (trackingFile.exists()))
266: trackingFile.delete();
267: throw new BuildException("Could not write update tracking",
268: e);
269: }
270: }
271:
272: protected void setTrackingFile(File dir, String tFname)
273: throws BuildException {
274: this .trackingFile = new File(dir, tFname);
275: // this.trackingFile.mkdirs();
276: try {
277: //setTrackingOutputStream(new FileOutputStream(this.trackingFile));
278: if (this .trackingFile.exists())
279: setTrackingInputStream(new FileInputStream(
280: this .trackingFile));
281: } catch (java.io.FileNotFoundException fnf) {
282: throw new BuildException("Unable to find tracking file "
283: + this .trackingFile.getAbsolutePath(), fnf);
284: }
285: }
286:
287: public void setTrackingOutputStream(OutputStream tos) {
288: this .os = tos;
289: }
290:
291: public OutputStream getTrackingOutputStream() {
292: return this .os;
293: }
294:
295: public void setTrackingInputStream(InputStream tis) {
296: this .is = tis;
297: }
298:
299: public String getTrackingFileName() throws BuildException {
300: String trackingFileName = module.getCodenamebase();
301: if ((trackingFileName == null)
302: || (trackingFileName.length() == 0))
303: throw new BuildException(
304: "Empty codenamebase, unable to locate tracking file");
305: trackingFileName = trackingFileName.replace('.', '-') + ".xml"; //NOI18N
306: return trackingFileName;
307: }
308:
309: /** Scan through Document document. */
310: private void read() throws BuildException {
311: /** Document document */
312: Document document;
313: if (this .is == null) {
314: File directory = new File(nbPath + FILE_SEPARATOR
315: + TRACKING_DIRECTORY);
316: if (!directory.exists()) {
317: directory.mkdirs();
318: }
319: setTrackingFile(directory, getTrackingFileName());
320: }
321: try {
322: InputSource xmlInputSource = new InputSource(this .is);
323: document = XMLUtil.parse(xmlInputSource, false, false,
324: new ErrorCatcher(), null);
325: if (is != null)
326: is.close();
327: } catch (org.xml.sax.SAXException e) {
328: e.printStackTrace();
329: if (trackingFile == null) {
330: throw new BuildException(
331: "Update tracking data in external InputStream is not well formatted XML document.",
332: e);
333: } else {
334: throw new BuildException("Update tracking file "
335: + trackingFile.getAbsolutePath()
336: + " is not well formatted XML document.", e);
337: }
338: } catch (java.io.IOException e) {
339: e.printStackTrace();
340: if (trackingFile == null) {
341: throw new BuildException(
342: "I/O error while accessing tracking data in InputStream",
343: e);
344: } else {
345: throw new BuildException(
346: "I/O error while accessing tracking file "
347: + trackingFile.getAbsolutePath(), e);
348: }
349: }
350:
351: Element element = document.getDocumentElement();
352: if ((element != null)
353: && element.getTagName().equals(ELEMENT_MODULE)) {
354: scanElement_module(element);
355: }
356: }
357:
358: /** Scan through Element named module. */
359: void scanElement_module(Element element) { // <module>
360: module = new Module();
361: NamedNodeMap attrs = element.getAttributes();
362: for (int i = 0; i < attrs.getLength(); i++) {
363: Attr attr = (Attr) attrs.item(i);
364: if (attr.getName().equals(ATTR_CODENAME)) { // <module codename="???">
365: module.setCodename(attr.getValue());
366: }
367: }
368: NodeList nodes = element.getChildNodes();
369: for (int i = 0; i < nodes.getLength(); i++) {
370: Node node = nodes.item(i);
371: if (node.getNodeType() == Node.ELEMENT_NODE) {
372: Element nodeElement = (Element) node;
373: if (nodeElement.getTagName().equals(ELEMENT_VERSION)) {
374: scanElement_module_version(nodeElement, module);
375: }
376: }
377: }
378: }
379:
380: /** Scan through Element named module_version. */
381: void scanElement_module_version(Element element, Module module) { // <module_version>
382: Version version = new Version();
383: NamedNodeMap attrs = element.getAttributes();
384: for (int i = 0; i < attrs.getLength(); i++) {
385: Attr attr = (Attr) attrs.item(i);
386: if (attr.getName().equals(ATTR_VERSION)) { // <module_version specification_version="???">
387: version.setVersion(attr.getValue());
388: }
389: if (attr.getName().equals(ATTR_ORIGIN)) { // <module_version origin="???">
390: version.setOrigin(attr.getValue());
391: }
392: if (attr.getName().equals(ATTR_LAST)) { // <module_version last="???">
393: version.setLast(Boolean.getBoolean(attr.getValue()));
394: }
395: if (attr.getName().equals(ATTR_INSTALL)) { // <module_version install_time="???">
396: long li = 0;
397: try {
398: li = Long.parseLong(attr.getValue());
399: } catch (NumberFormatException nfe) {
400: }
401: version.setInstall_time(li);
402: }
403: }
404: NodeList nodes = element.getChildNodes();
405: for (int i = 0; i < nodes.getLength(); i++) {
406: Node node = nodes.item(i);
407: if (node.getNodeType() == Node.ELEMENT_NODE) {
408: Element nodeElement = (Element) node;
409: if (nodeElement.getTagName().equals(ELEMENT_FILE)) {
410: scanElement_file(nodeElement, version);
411: }
412: }
413: }
414: module.addVersion(version);
415: }
416:
417: /** Scan through Element named file. */
418: void scanElement_file(Element element, Version version) { // <file>
419: ModuleFile file = new ModuleFile();
420: NamedNodeMap attrs = element.getAttributes();
421: for (int i = 0; i < attrs.getLength(); i++) {
422: Attr attr = (Attr) attrs.item(i);
423: if (attr.getName().equals(ATTR_FILE_NAME)) { // <file name="???">
424: file.setName(attr.getValue().replace(
425: File.separatorChar, '/'));
426: }
427: if (attr.getName().equals(ATTR_CRC)) { // <file crc="???">
428: file.setCrc(attr.getValue());
429: }
430: }
431: version.addFile(file);
432: }
433:
434: class Module extends Object {
435:
436: /** Holds value of property codename. */
437: private String codename;
438:
439: /** Holds value of property versions. */
440: private List<Version> versions = new ArrayList<Version>();
441:
442: /** Getter for property codenamebase.
443: * @return Value of property codenamebase.
444: */
445: String getCodenamebase() {
446: String codenamebase = new String(codename);
447: int idx = codenamebase.lastIndexOf('/'); //NOI18N
448: if (idx != -1)
449: codenamebase = codenamebase.substring(0, idx);
450:
451: return codenamebase;
452: }
453:
454: /** Getter for property codename.
455: * @return Value of property codename.
456: */
457: String getCodename() {
458: return codename;
459: }
460:
461: /** Setter for property codename.
462: * @param codename New value of property codename.
463: */
464: void setCodename(String codename) {
465: this .codename = codename;
466: }
467:
468: /** Getter for property versions.
469: * @return Value of property versions.
470: */
471: List<Version> getVersions() {
472: return versions;
473: }
474:
475: /** Setter for property versions.
476: * @param versions New value of property versions.
477: */
478: void setVersions(List<Version> versions) {
479: this .versions = versions;
480: }
481:
482: void addVersion(Version version) {
483: versions = new ArrayList<Version>();
484: versions.add(version);
485: }
486:
487: void setVersion(Version version) {
488: versions = new ArrayList<Version>();
489: versions.add(version);
490: }
491:
492: void removeLocalized(String locale) {
493: Iterator it = versions.iterator();
494: while (it.hasNext()) {
495: Version ver = (Version) it.next();
496: ver.removeLocalized(locale);
497: }
498: }
499: }
500:
501: public class Version extends Object {
502:
503: /** Holds value of property version. */
504: private String version;
505:
506: /** Holds value of property origin. */
507: private String origin;
508:
509: /** Holds value of property last. */
510: private boolean last;
511:
512: /** Holds value of property install_time. */
513: private long install_time = 0;
514:
515: /** Holds value of property files. */
516: private List<ModuleFile> files = new ArrayList<ModuleFile>();
517:
518: /** Getter for property version.
519: * @return Value of property version.
520: */
521: String getVersion() {
522: return version;
523: }
524:
525: /** Setter for property version.
526: * @param version New value of property version.
527: */
528: void setVersion(String version) {
529: this .version = version;
530: }
531:
532: /** Getter for property origin.
533: * @return Value of property origin.
534: */
535: String getOrigin() {
536: return origin;
537: }
538:
539: /** Setter for property origin.
540: * @param origin New value of property origin.
541: */
542: void setOrigin(String origin) {
543: this .origin = origin;
544: }
545:
546: /** Getter for property last.
547: * @return Value of property last.
548: */
549: boolean isLast() {
550: return last;
551: }
552:
553: /** Setter for property last.
554: * @param last New value of property last.
555: */
556: void setLast(boolean last) {
557: this .last = last;
558: }
559:
560: /** Getter for property install_time.
561: * @return Value of property install_time.
562: */
563: long getInstall_time() {
564: return install_time;
565: }
566:
567: /** Setter for property install_time.
568: * @param install_time New value of property install_time.
569: */
570: void setInstall_time(long install_time) {
571: this .install_time = install_time;
572: }
573:
574: /** Getter for property files.
575: * @return Value of property files.
576: */
577: List<ModuleFile> getFiles() {
578: return files;
579: }
580:
581: /** Setter for property files.
582: * @param files New value of property files.
583: */
584: void setFiles(List<ModuleFile> files) {
585: this .files = files;
586: }
587:
588: void addFile(ModuleFile file) {
589: files.add(file);
590: }
591:
592: public void addFileWithCrc(String filename, String crc) {
593: ModuleFile file = new ModuleFile();
594: file.setName(filename);
595: file.setCrc(crc);
596: files.add(file);
597: }
598:
599: public void removeLocalized(String locale) {
600: List<ModuleFile> newFiles = new ArrayList<ModuleFile>();
601: for (ModuleFile file : files) {
602: if (file.getName().indexOf("_" + locale + ".") == -1 // NOI18N
603: && file.getName().indexOf("_" + locale + "/") == -1 // NOI18N
604: && !file.getName().endsWith("_" + locale)) // NOI18N
605: newFiles.add(file);
606: }
607: files = newFiles;
608:
609: }
610:
611: }
612:
613: class ModuleFile extends Object {
614:
615: /** Holds value of property name. */
616: private String name;
617:
618: /** Holds value of property crc. */
619: private String crc;
620:
621: /** Getter for property name.
622: * @return Value of property name.
623: */
624: String getName() {
625: return name;
626: }
627:
628: /** Setter for property name.
629: * @param name New value of property name.
630: */
631: void setName(String name) {
632: this .name = name.replace(File.separatorChar, '/');
633: }
634:
635: /** Getter for property crc.
636: * @return Value of property crc.
637: */
638: String getCrc() {
639: return crc;
640: }
641:
642: /** Setter for property crc.
643: * @param crc New value of property crc.
644: */
645: void setCrc(String crc) {
646: this .crc = crc;
647: }
648:
649: }
650:
651: class ErrorCatcher implements ErrorHandler {
652: public void error(SAXParseException e) {
653: // normally a validity error
654: pError = true;
655: }
656:
657: public void warning(SAXParseException e) {
658: //parseFailed = true;
659: }
660:
661: public void fatalError(SAXParseException e) {
662: pError = true;
663: }
664: }
665:
666: }
|