001: /*
002: * ParFileBuilder.java
003: *
004: * Created on October 29, 2001, 10:50 AM
005: */
006:
007: package com.sun.portal.desktop.deployment;
008:
009: import java.io.InputStream;
010: import java.io.PrintStream;
011: import java.io.ByteArrayOutputStream;
012:
013: import java.util.Map;
014: import java.util.HashMap;
015: import java.util.Vector;
016: import java.util.List;
017: import java.util.Set;
018: import java.util.Iterator;
019: import java.util.Properties;
020:
021: import java.util.logging.Level;
022: import java.util.logging.Logger;
023:
024: import java.util.zip.ZipEntry;
025:
026: import org.w3c.dom.Document;
027:
028: /**
029: * ParFile Builder sequences operations for the construction of .par files.
030: *
031: * This class hides the manipulation of the manifest, and enforces correct
032: * sequencing of operations, since you have to build up the manifest before
033: * streaming a jar.
034: *
035: * This is used by calling addDPEntry() for every file entry, providing the
036: * DP document and the list of files associated with the entry. Then,
037: * makeParFile() is called which streams out the .par file,
038: * clearing the ParFileBUilder for a fresh operation.
039: *
040: * @author yabob
041: * @version
042: */
043: public class ParFileBuilder {
044:
045: // This is called from the MBean, a logger is passed in and
046: // it is used for debugging statements, in this case m_Out is not used.
047: public ParFileBuilder(boolean verbose, Logger logger,
048: String backupVersion) {
049: m_Verbose = verbose;
050: m_Logger = logger;
051: m_BackupVersion = backupVersion;
052: Par.setLogger(logger);
053: }
054:
055: public ParFileBuilder(boolean verbose, PrintStream out) {
056: m_DefaultManifest = true;
057: m_Verbose = verbose;
058: m_Out = out;
059: }
060:
061: // Like the manifest, we can either specify the roots, or
062: // default them.
063: public ParFileBuilder(boolean verbose, PrintStream out,
064: String classroot, String dproot, String pbfileroot,
065: String statroot, String warroot, String confroot) {
066: this (verbose, out);
067: m_DefaultManifest = false;
068: m_CRoot = classroot;
069: m_DPRoot = dproot;
070: m_PBFRoot = pbfileroot;
071: m_SRoot = statroot;
072: m_WRoot = warroot;
073: m_ConfRoot = confroot;
074: }
075:
076: // clear the builder to start a new .par file.
077:
078: public void clear() {
079: m_FileLists.clear();
080: m_Man = null;
081: }
082:
083: // This version of addDPEntry takes a Map which contains dn, XML
084: // document pairs, a vector of ProviderPackageFile's which contain
085: // the files (other than the document) associated with the entry,
086: // and a list of identity service attribute names.
087: public void addDPEntry(String name, Map docs, Vector files,
088: Map properties, ExtractOp op) throws ParFileException {
089: // We create a manifest on the first call.
090: assureManifest();
091:
092: // clone the file list, since we are holding it in our hash table. This
093: // way, the caller can reuse their vector. We obtain the name for our entry
094: // from the XML document. We also need to copy the list because we are
095: // going to add an entry to it (see below).
096:
097: Vector fc = (Vector) files.clone();
098:
099: if (m_Verbose) {
100: if (m_Logger != null && m_Logger.isLoggable(Level.INFO)) {
101: m_Logger.log(Level.INFO,
102: "ParFileBuilder.addDPEntry(): Add ManifestEntry for:"
103: + name);
104: }
105: }
106:
107: // add manifest entry, then loop through the vector, adding inclusions
108: m_Man.addDPEntry(name);
109:
110: // add files inclusion
111: for (int i = 0; i < fc.size(); ++i) {
112: ProviderPackageFile ppf = (ProviderPackageFile) fc
113: .elementAt(i);
114: ppf.addManifestInclusion(m_Man, name);
115: }
116:
117: // add the extract op, if specified.
118:
119: if (op != null) {
120: m_Man.addDPEntryAutoExtract(name, op);
121: if (m_Verbose) {
122: if (m_Logger != null && m_Logger.isLoggable(Level.INFO)) {
123: m_Logger.log(Level.INFO,
124: "ParFileBuilder.addDPEntry(): Autoextract:"
125: + op.toArg());
126: }
127: }
128: }
129:
130: // Now, add an entry for every XML doc to the file vector,
131: // so we will actually archive it, and store our copy of the list.
132:
133: if (docs != null && !docs.isEmpty()) {
134: Set keys = docs.keySet();
135:
136: for (Iterator i = keys.iterator(); i.hasNext();) {
137: String key = (String) i.next();
138: Document doc = (Document) docs.get(key);
139:
140: fc.add(new DPDocDomPPF(doc, key));
141: }
142:
143: m_Man.addDPEntryDPDocs(name, keys);
144: }
145:
146: // Add attribute properties files into fc
147: if (properties != null && !properties.isEmpty()) {
148: Set keys = properties.keySet();
149:
150: for (Iterator i = keys.iterator(); i.hasNext();) {
151: String key = (String) i.next();
152: fc.add(new PropertiesPPF((Properties) properties
153: .get(key), 0, key));
154: }
155:
156: m_Man.addDPEntryAttrProps(name, keys);
157: }
158:
159: // finally put all PPF files in fc into the file lists
160: m_FileLists.put(name, fc);
161:
162: }
163:
164: // addDPEntry takes the paretry XML document, and a vector of ProviderPackageFile's
165: // which contain the files (other than the document) associated with the entry. Optionally,
166: // an ExtractOp may be specified along with it, which becomes the automatic extract operation
167: // for this entry
168:
169: public void addDPEntry(Document doc, Vector files, ExtractOp op)
170: throws ParFileException {
171:
172: // We create a manifest on the first call.
173:
174: assureManifest();
175:
176: // clone the file list, since we are holding it in our hash table. This
177: // way, the caller can reuse their vector. We obtain the name for our entry
178: // from the XML document. We also need to copy the list because we are
179: // going to add an entry to it (see below).
180:
181: Vector fc = (Vector) files.clone();
182: String name = Par.findDPEntryName(doc);
183:
184: // we will also add any existing files to the list. These come at the BACK, so
185: // that newer ones take precedence. After this point, we also use vold != null
186: // as an indicator that we have an old entry.
187:
188: Vector vold = (Vector) m_FileLists.get(name);
189: if (vold != null) {
190: int len = vold.size() - 1; // last entry is the old XML - we don't want it.
191: for (int i = 0; i < len; ++i) {
192: fc.add(vold.elementAt(i));
193: }
194: }
195:
196: // add manifest entry, then loop through the vector, adding inclusions
197:
198: if (m_Verbose) {
199: Object tok[] = { name };
200: if (m_Out != null) {
201: m_Out.println(Par.getLocalizedString(
202: "msgAddManifestEntry", tok));
203: }
204: }
205:
206: // Note - ParManifest handles multiple references to the same file inclusion,
207: // so it doesn't matter that we may have already called addManifestInclusion
208: // for some of these files. It IS an error to attempt to recreate an entry.
209:
210: if (vold == null) {
211: m_Man.addDPEntry(name);
212: }
213: for (int i = 0; i < fc.size(); ++i) {
214: ProviderPackageFile ppf = (ProviderPackageFile) fc
215: .elementAt(i);
216: ppf.addManifestInclusion(m_Man, name);
217: }
218:
219: // add the extract op, if specified.
220:
221: if (op != null) {
222: m_Man.addDPEntryAutoExtract(name, op);
223: if (m_Verbose) {
224: if (m_Out != null) {
225: m_Out.println("\tAutoextract - " + op.toArg());
226: }
227: }
228: }
229:
230: // Now, add an entry to the file vector for the XML doc, so we will actually
231: // archive it, and store our copy of the list.
232:
233: fc.add(new ParEntryDomPPF(doc, name));
234: m_FileLists.put(name, fc);
235: }
236:
237: public void addDPEntry(Document doc, Vector files)
238: throws ParFileException {
239: addDPEntry(doc, files, null);
240: }
241:
242: // Having added all the entries, make the .par file at a given location.
243: //
244: // This also clears everything again for a fresh .par file.
245:
246: public void makeParFile(String path) throws ParFileException {
247:
248: if (m_Man == null) {
249: throw new ParFileException("errorEmptyPar");
250: }
251:
252: if (m_Verbose) {
253: Object tok[] = { path };
254: if (m_Out != null) {
255: m_Out.println(Par
256: .getLocalizedString("msgStreamTo", tok));
257: }
258: if (m_Logger != null && m_Logger.isLoggable(Level.INFO)) {
259: m_Logger.log(Level.INFO,
260: "ParFileBuider.makeParFile(), message streamed to: "
261: + path);
262: }
263: }
264:
265: try {
266: // This creates the archive stream, and streams out the manifest.
267:
268: ParOutputStream pos = new ParOutputStream(path, m_Man);
269:
270: // get the entry list from the manifest, and loop through, streaming out
271: // the contents based on our stored vector of files.
272:
273: Vector ev = m_Man.getDPEntryList();
274: for (int i = 0; i < ev.size(); ++i) {
275: String name = (String) ev.elementAt(i);
276: streamEntry(pos, name, true);
277: }
278:
279: // Done. Close the stream.
280:
281: pos.close();
282: } catch (Exception ex) {
283: throw new ParFileException("errorParStream", ex);
284: }
285:
286: clear();
287: }
288:
289: // Make a par and write everything in the
290: // ByeArrayOurputStream that's given
291: public void makePar(String path, ByteArrayOutputStream out)
292: throws ParFileException {
293: if (m_Man == null) {
294: throw new ParFileException("errorEmptyPar");
295: }
296:
297: if (m_Verbose) {
298: if (m_Logger != null && m_Logger.isLoggable(Level.INFO)) {
299: m_Logger.log(Level.INFO,
300: "ParFileBuilder.makePar(), Making par for: "
301: + path);
302: }
303: }
304:
305: try {
306: // This creates the archive stream, and streams out the manifest.
307:
308: ParOutputStream pos = new ParOutputStream(out, m_Man);
309:
310: // get the entry list from the manifest, and loop
311: // through, streaming out the contents based on our
312: // stored vector of files.
313:
314: Vector ev = m_Man.getDPEntryList();
315: for (int i = 0; i < ev.size(); ++i) {
316: String nameEnt = (String) ev.elementAt(i);
317: streamEntry(pos, nameEnt, false);
318: }
319:
320: // Done. Close the stream.
321:
322: pos.close();
323: } catch (Exception ex) {
324: throw new ParFileException("errorParStream", ex);
325: }
326:
327: clear();
328: }
329:
330: // Stream out files for a particular entry, to our open archive stream.
331:
332: private void streamEntry(ParOutputStream pos, String name,
333: boolean checkName) throws ParFileException {
334:
335: Vector files = (Vector) m_FileLists.get(name);
336:
337: // Process our files. For each one, we get the appropriate zip entry for it,
338: // which is needed to start a new archive entry (overloaded term - don't confuse
339: // this with a manifest entry). Then, we just get a stream from it, and transfer
340: // between it and the archive output stream.
341:
342: byte buf[] = new byte[4000];
343: int len;
344: HashMap namecheck = new HashMap();
345:
346: try {
347: for (int i = 0; i < files.size(); ++i) {
348: ProviderPackageFile ppf = (ProviderPackageFile) files
349: .elementAt(i);
350: ZipEntry ze = ppf.getZipEntry(m_Man);
351: String nm = ze.getName();
352: if (checkName) {
353: if (namecheck.get(nm) != null) {
354: continue;
355: }
356: namecheck.put(nm, nm);
357: }
358:
359: if (m_Verbose) {
360: Object tok[] = { nm };
361: if (m_Out != null) {
362: m_Out.println(Par.getLocalizedString(
363: "msgArchiving", tok));
364: }
365: if (m_Logger != null
366: && m_Logger.isLoggable(Level.INFO)) {
367: m_Logger.log(Level.INFO,
368: "ParFileBuilder.streamEntry(), Archiving: "
369: + nm);
370: }
371:
372: }
373: pos.putNextEntry(ze);
374: InputStream is = ppf.getStream();
375: while ((len = is.read(buf)) > 0) {
376: pos.write(buf, 0, len);
377: }
378: is.close();
379: }
380: } catch (Exception ex) {
381: throw new ParFileException("errorParStream", ex);
382: }
383: }
384:
385: private void assureManifest() {
386:
387: if (m_Man != null) {
388: return;
389: }
390:
391: if (m_BackupVersion != null) {
392: m_Man = new ParManifest(m_BackupVersion);
393: return;
394: }
395:
396: if (m_DefaultManifest) {
397: m_Man = new ParManifest();
398: return;
399: }
400: m_Man = new ParManifest(m_CRoot, m_DPRoot, m_PBFRoot, m_SRoot,
401: m_WRoot, m_ConfRoot, null);
402: }
403:
404: private HashMap m_FileLists = new HashMap();
405: private ParManifest m_Man = null;
406: private boolean m_DefaultManifest;
407: private String m_CRoot;
408: private String m_DPRoot;
409: private String m_PBFRoot;
410: private String m_SRoot;
411: private String m_WRoot;
412: private String m_ConfRoot;
413: private boolean m_Verbose;
414: private PrintStream m_Out;
415: private Logger m_Logger;
416: private String m_BackupVersion;
417: }
|