001: /**
002: * $Id: PortalWar.java,v 1.20 2007/01/26 03:48:33 portalbld Exp $
003: * Copyright 2004 Sun Microsystems, Inc. All
004: * rights reserved. Use of this product is subject
005: * to license terms. Federal Acquisitions:
006: * Commercial Software -- Government Users
007: * Subject to Standard License Terms and
008: * Conditions.
009: *
010: * Sun, Sun Microsystems, the Sun logo, and Sun ONE
011: * are trademarks or registered trademarks of Sun Microsystems,
012: * Inc. in the United States and other countries.
013: */package com.sun.portal.fabric.tasks;
014:
015: import java.io.File;
016: import java.io.FileInputStream;
017: import java.io.FileOutputStream;
018: import java.io.BufferedInputStream;
019: import java.io.BufferedOutputStream;
020: import java.io.BufferedReader;
021: import java.io.FileReader;
022: import java.io.FileNotFoundException;
023: import java.io.InputStreamReader;
024: import java.io.IOException;
025: import java.io.StringWriter;
026: import java.io.InputStream;
027: import java.io.OutputStream;
028: import java.util.List;
029: import java.util.ArrayList;
030: import java.util.Iterator;
031: import java.util.jar.JarEntry;
032: import java.util.jar.JarOutputStream;
033: import java.util.Properties;
034: import java.util.zip.ZipEntry;
035: import java.util.zip.ZipInputStream;
036: import java.util.logging.Level;
037: import java.util.logging.Logger;
038: import java.util.logging.LogRecord;
039:
040: import javax.xml.parsers.DocumentBuilderFactory;
041: import javax.xml.parsers.DocumentBuilder;
042: import javax.xml.transform.Transformer;
043: import javax.xml.transform.TransformerFactory;
044: import javax.xml.transform.OutputKeys;
045: import javax.xml.transform.dom.DOMSource;
046: import javax.xml.transform.stream.StreamResult;
047: import org.xml.sax.ErrorHandler;
048: import org.xml.sax.SAXParseException;
049: import org.xml.sax.SAXException;
050: import org.xml.sax.InputSource;
051:
052: import org.w3c.dom.Document;
053: import org.w3c.dom.DocumentType;
054: import org.w3c.dom.Node;
055: import org.w3c.dom.NodeList;
056: import org.w3c.dom.Element;
057:
058: import com.sun.portal.fabric.util.FileUtil;
059: import com.sun.portal.admin.common.Tags;
060: import com.sun.portal.admin.common.PSConfigConstants;
061: import com.sun.portal.util.DTDResolver;
062: import com.sun.portal.log.common.PortalLogger;
063: import com.sun.portal.util.Platform;
064:
065: public class PortalWar {
066:
067: private static final String FS = Platform.fs;
068: private static final char SEPARATOR = '/';
069: private static final char DELIMITER = '|';
070: private static final String DOCTYPE_PUBLIC = "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN";
071: private static final String DOCTYPE_SYSTEM = "http://java.sun.com/dtd/web-app_2_3.dtd";
072:
073: //Initialized by constructor
074: private String productDir = null; //ex. /opt/SUNWps
075: private String psDataDir = null; //ex. /var/opt/SUNWps
076: private String psConfigDir = null; //ex. /etc/opt/SUNps
077: private String shareLibLoc = null; //ex. /usr/share/lib
078: private String commonWebSrc = null; //ex. /opt/SUNWps/web-src
079: private String portalDir = null; //ex. /var/opt/SUNWps/portals/portal1
080: private String searchDir = null; //ex. /var/opt/SUNWps/searchservers/portal1
081: private String portalWebSrc = null; //ex. /var/opt/SUNWps/portals/portal1/web-src
082: private String tempDir = null; //ex. /var/opt/SUNWps/tmp/12345678
083: private String tempWebSrc = null; //ex. /var/opt/SUNWps/tmp/12345678/web-src
084: private String portalWarDir = null; //ex. /var/opt/SUNWps/portal/portal1/war
085: private String portalWar = null; //ex. /var/opt/SUNWps/portals/portal1/war/portal.war
086: private String desktopDocDir = null; //ex. /opt/SUNWps/sdk/desktop
087: private String wsrpDocDir = null; //ex. /opt/SUNWps/sdk/wsrp
088: private String javadocFile = "javadocs.jar";
089: private String javadocDestFolder = null; //ex. /opt/SUNWps/web-src/javadocs/
090: private Properties psConfigProps = new Properties();
091: private static Logger logger = PortalLogger
092: .getLogger(PortalWar.class);
093:
094: public PortalWar(String portalId, String psConfigFile)
095: throws ConfigurationException {
096:
097: try {
098: FileInputStream fis = new FileInputStream(psConfigFile);
099: psConfigProps.load(fis);
100: fis.close();
101: } catch (IOException ioe) {
102: throw new ConfigurationException(ioe);
103: }
104:
105: productDir = psConfigProps
106: .getProperty(PSConfigConstants.PS_BASE_DIR);
107: psDataDir = psConfigProps
108: .getProperty(PSConfigConstants.PS_DATA_DIR);
109: psConfigDir = psConfigProps
110: .getProperty(PSConfigConstants.PS_CONFIG_DIR);
111: shareLibLoc = psConfigProps
112: .getProperty(PSConfigConstants.SHARED_LIB_DIR);
113: tempDir = psDataDir + FS + "tmp" + FS
114: + FileUtil.getRandomDirName();
115: commonWebSrc = productDir + FS + "web-src";
116: tempWebSrc = tempDir + FS + "web-src";
117: portalDir = psDataDir + FS + "portals" + FS + portalId;
118: searchDir = psDataDir + FS + "searchservers" + FS + portalId;
119: portalWebSrc = portalDir + FS + "web-src";
120: desktopDocDir = productDir + FS + "sdk" + FS + "desktop";
121: wsrpDocDir = productDir + FS + "sdk" + FS + "wsrp";
122: javadocDestFolder = commonWebSrc + FS + "javadocs";
123: }
124:
125: public void create(String warFileName)
126: throws ConfigurationException {
127: portalWarDir = portalDir + FS + "war";
128: if (warFileName != null && warFileName.endsWith(".war")) {
129: portalWar = portalWarDir + FS + warFileName;
130: } else {
131: portalWar = portalWarDir + FS + "portal.war";
132: }
133: importExternalFiles();
134: extractAPIDocs();
135: mergeWebXml();
136: createWarFile();
137:
138: // Copy over the Community Manager WebServices warfile to deploy dir
139: String srcFileName = productDir + FS + "export" + FS
140: + "communitymanagerwebservices.war";
141: String destFileName = portalWarDir + FS
142: + "communitymanagerwebservices.war";
143: File srcFile = new File(srcFileName);
144: if (srcFile.exists()) {
145: FileUtil.copyFile(srcFileName, destFileName);
146: }
147: }
148:
149: private void extractAPIDocs() {
150: try {
151: InputStream desktopDocJar = new FileInputStream(
152: desktopDocDir + FS + javadocFile);
153: extract(desktopDocJar, javadocDestFolder + FS + "desktop");
154: } catch (FileNotFoundException e) {
155: if (logger.isLoggable(Level.WARNING)) {
156: LogRecord rec = new LogRecord(Level.SEVERE,
157: "PSFB_CSPFT0321");
158: rec.setLoggerName(logger.getName());
159: rec.setParameters(new Object[] { desktopDocDir + FS
160: + javadocFile });
161: rec.setThrown(e);
162: logger.log(rec);
163: }
164: } catch (IOException e) {
165: if (logger.isLoggable(Level.WARNING)) {
166: LogRecord rec = new LogRecord(Level.SEVERE,
167: "PSFB_CSPFT0322");
168: rec.setLoggerName(logger.getName());
169: rec.setParameters(new Object[] { desktopDocDir + FS
170: + javadocFile });
171: rec.setThrown(e);
172: logger.log(rec);
173: }
174: }
175: try {
176: InputStream wsrpDocJar = new FileInputStream(wsrpDocDir
177: + FS + javadocFile);
178: extract(wsrpDocJar, javadocDestFolder + FS + "wsrp");
179: } catch (FileNotFoundException e) {
180: if (logger.isLoggable(Level.WARNING)) {
181: LogRecord rec = new LogRecord(Level.SEVERE,
182: "PSFB_CSPFT0323");
183: rec.setLoggerName(logger.getName());
184: rec.setParameters(new Object[] { wsrpDocDir + FS
185: + javadocFile });
186: rec.setThrown(e);
187: logger.log(rec);
188: }
189: } catch (IOException e) {
190: if (logger.isLoggable(Level.WARNING)) {
191: LogRecord rec = new LogRecord(Level.SEVERE,
192: "PSFB_CSPFT0324");
193: rec.setLoggerName(logger.getName());
194: rec.setParameters(new Object[] { wsrpDocDir + FS
195: + javadocFile });
196: rec.setThrown(e);
197: logger.log(rec);
198: }
199: }
200: }
201:
202: /*
203: * Extracts entries from JAR file.
204: */
205: void extract(InputStream in, String destFolder) throws IOException {
206: ZipInputStream zis = new ZipInputStream(in);
207: ZipEntry e;
208: while ((e = zis.getNextEntry()) != null) {
209: extractFile(zis, e, destFolder);
210: }
211: }
212:
213: /*
214: * Extracts next entry from JAR file, creating directories as needed.
215: */
216: void extractFile(ZipInputStream zis, ZipEntry e, String destFolder)
217: throws IOException {
218: String dest = destFolder.endsWith(FS) ? destFolder : destFolder
219: + FS;
220: File f = null;
221: f = new File(dest + e.getName());
222: if (e.isDirectory()) {
223: if (!f.exists() && !f.mkdirs() || !f.isDirectory()) {
224: throw new IOException("Error creating directory "
225: + f.getPath());
226: }
227: } else {
228: if (f.getParent() != null) {
229: File d = new File(f.getParent());
230: if (!d.exists() && !d.mkdirs() || !d.isDirectory()) {
231: throw new IOException("Error creating directory "
232: + d.getPath());
233: }
234: }
235: OutputStream os = new FileOutputStream(f);
236: byte[] b = new byte[512];
237: int len;
238: while ((len = zis.read(b, 0, b.length)) != -1) {
239: os.write(b, 0, len);
240: }
241: zis.closeEntry();
242: os.close();
243: }
244: }
245:
246: private void mergeWebXml() throws ConfigurationException {
247: List webXMLFilesVector = new ArrayList(100);
248:
249: //get all files from common area
250: String webXMLFilesDirPath = commonWebSrc + FS + "WEB-INF" + FS
251: + "xml";
252: logger.log(Level.FINEST, "PSFB_CSPFT0286", webXMLFilesDirPath);
253: File webXmlFilesDir = new File(webXMLFilesDirPath);
254: FileUtil.getFiles(webXmlFilesDir, webXMLFilesVector, "xml");
255:
256: //get all files from portal specific area
257: webXMLFilesDirPath = portalWebSrc + FS + "WEB-INF" + FS + "xml";
258: logger.log(Level.FINEST, "PSFB_CSPFT0287", webXMLFilesDirPath);
259: webXmlFilesDir = new File(webXMLFilesDirPath);
260: if (webXmlFilesDir.isDirectory()) {
261: FileUtil.getFiles(webXmlFilesDir, webXMLFilesVector, "xml");
262: }
263:
264: String fName = tempWebSrc + FS + "WEB-INF" + FS + "web.xml";
265: File mergedWebXMLFile = new File(fName);
266: if (mergedWebXMLFile.exists()) {
267: logger.log(Level.FINEST, "PSFB_CSPFT0288", fName);
268: mergedWebXMLFile.delete();
269: }
270:
271: logger.log(Level.FINEST, "PSFB_CSPFT0289", fName);
272: mergeWebXMLFiles(webXMLFilesVector, mergedWebXMLFile);
273: }
274:
275: private void importExternalFiles() throws ConfigurationException {
276: BufferedReader reader = null;
277: try {
278: String importFile = productDir + FS + "lib" + FS
279: + "war.import";
280: logger.log(Level.FINEST, "PSFB_CSPFT0290", importFile);
281: File warImport = new File(importFile);
282: reader = new BufferedReader(new FileReader(warImport));
283:
284: String line = null;
285: while ((line = reader.readLine()) != null) {
286: if (line.startsWith("#")) {
287: //comment, skip.
288: logger.log(Level.FINEST, "PSFB_CSPFT0291", line);
289: continue;
290: }
291: String[] srcDest = line.split("\\" + DELIMITER);
292: if ((srcDest.length != 2) && (srcDest.length != 3)) {
293: //incorrect format-src ends with backslash, skip.
294: logger.log(Level.FINEST, "PSFB_CSPFT0292", line);
295: continue;
296: }
297: String src = srcDest[0];
298: String dest = srcDest[1];
299:
300: int index = src.indexOf(SEPARATOR);
301: if (index == -1) {
302: logger.log(Level.SEVERE, "PSFB_CSPFT0293", line);
303: throw new ConfigurationException(
304: "Illegal war.import file");
305: }
306:
307: String key = src.substring(0, index);
308: src = src.substring(index);
309: src = psConfigProps.getProperty(key, key) + src;
310:
311: dest = tempWebSrc + FS + dest;
312:
313: if (FileUtil.directoryExists(src)) {
314: logger.log(Level.FINEST, "PSFB_CSPFT0294",
315: new Object[] { src, dest });
316: FileUtil.copyDir(src, dest);
317: } else if (FileUtil.fileExists(src)) {
318: logger.log(Level.FINEST, "PSFB_CSPFT0294",
319: new Object[] { src, dest });
320: FileUtil.copyFile(src, dest);
321: } else if ((srcDest.length > 2)
322: && srcDest[2].equalsIgnoreCase("*")) {
323: // This is optional, so skip it.
324: logger.log(Level.FINEST, "PSFB_CSPFT0325",
325: new Object[] { src, dest });
326: }
327: }
328: logger.log(Level.FINEST, "PSFB_CSPFT0295", importFile);
329: } catch (FileNotFoundException fex) {
330: throw new ConfigurationException(fex.toString());
331: } catch (IOException ioex) {
332: throw new ConfigurationException(ioex.toString());
333: } finally {
334: try {
335: reader.close();
336: } catch (IOException ioe) {
337: throw new ConfigurationException(ioe.toString());
338: }
339: }
340: }
341:
342: private void createWarFile() throws ConfigurationException {
343: JarOutputStream jar = null;
344: try {
345:
346: File psWar = new File(portalWar);
347: if (psWar.exists()) {
348: logger.log(Level.FINEST, "PSFB_CSPFT0296", portalWar);
349: psWar.delete();
350: }
351:
352: logger.log(Level.FINEST, "PSFB_CSPFT0297", psWar);
353: FileOutputStream dest = new FileOutputStream(psWar);
354:
355: try {
356: jar = new JarOutputStream(
357: new BufferedOutputStream(dest));
358: } catch (IOException ioe) {
359: dest.close();
360: throw new ConfigurationException(ioe);
361: }
362:
363: byte data[] = new byte[1024];
364:
365: List fileList = new ArrayList(100);
366: List entryList = new ArrayList(100);
367:
368: //First, copy the /var/opt/SUNWps/portals/?/web-src
369: //into /var/opt/SUNWps/tmp/random-dir/web-src
370: logger.log(Level.FINEST, "PSFB_CSPFT0298", new Object[] {
371: portalWebSrc, tempWebSrc });
372: FileUtil.copyDir(portalWebSrc, tempWebSrc);
373:
374: //Second, copy the /opt/SUNWps/web-src
375: //into /var/opt/SUNWps/tmp/random-dir/web-src
376: //This will overwrite the files that exist with same name
377: //This is to fix 6283262, so we overwrite customer files with
378: //same path and name as ours and do
379: //not allow to replace our files. Customers can only add.
380: logger.log(Level.FINEST, "PSFB_CSPFT0298", new Object[] {
381: commonWebSrc, tempWebSrc });
382: if (Platform.name.equals("windows"))
383: FileUtil.copyDir(commonWebSrc, tempWebSrc);
384: else
385: FileUtil.copyDir(commonWebSrc, tempWebSrc, false);
386:
387: //Third and last, create a war file out
388: //of /var/opt/SUNWps/tmp/random-dir/web-src
389: //get the file list
390: getFiles(new File(tempWebSrc), "", fileList, entryList);
391:
392: Iterator fileIter = fileList.iterator();
393: Iterator entryIter = entryList.iterator();
394:
395: while (fileIter.hasNext() && entryIter.hasNext()) {
396: File file = (File) fileIter.next();
397: JarEntry entry = new JarEntry((String) entryIter.next());
398: jar.putNextEntry(entry);
399: if (file.isDirectory()) {
400: continue;
401: }
402:
403: BufferedInputStream origin = new BufferedInputStream(
404: new FileInputStream(file), data.length);
405: try {
406: int bytesRead;
407: while ((bytesRead = origin.read(data, 0,
408: data.length)) != -1) {
409: jar.write(data, 0, bytesRead);
410: }
411: } finally {
412: origin.close();
413: jar.closeEntry();
414: }
415: //logger.log(Level.FINEST, "Added " + file.getName() + " to war");
416: }
417: logger.log(Level.FINEST, "PSFB_CSPFT0299", portalWar);
418: } catch (IOException ioe) {
419: logger.log(Level.SEVERE, "PSFB_CSPFT0300", ioe);
420: throw new ConfigurationException(ioe);
421: } finally {
422: try {
423: jar.close();
424: } catch (IOException ioe) {
425: logger.log(Level.SEVERE, "PSFB_CSPFT0300", ioe);
426: throw new ConfigurationException(ioe);
427: } finally {
428: logger.log(Level.FINEST, "PSFB_CSPFT0301", tempDir);
429: //delete the /var/opt/SUNWps/tmp/random-dir
430: FileUtil.deleteDir(tempDir);
431: }
432: }
433: }
434:
435: /**
436: * Builds a list of Files (absolute path) and a corresponding list of jar
437: * entry names (with forward slashes) by recursively entering the dir.
438: */
439: private void getFiles(File startDir, String jarPath, List fileList,
440: List entryList) {
441: File[] files = startDir.listFiles();
442: for (int i = 0; i < files.length; i++) {
443: File file = (File) files[i];
444: fileList.add(file);
445: if (file.isFile()) {
446: entryList.add(jarPath + file.getName());
447: } else if (file.isDirectory()) {
448: String currPath = jarPath + file.getName() + "/";
449: entryList.add(currPath);
450: getFiles(file, currPath, fileList, entryList);
451: }
452: }
453: }
454:
455: private void mergeWebXMLFiles(List webXMLFiles,
456: File mergedWebXMLFile) {
457: try {
458: DocumentBuilderFactory dbf = DocumentBuilderFactory
459: .newInstance();
460: dbf.setValidating(false);
461:
462: DocumentBuilder db = dbf.newDocumentBuilder();
463:
464: DTDResolver dtdReso = new DTDResolver();
465: db.setEntityResolver(dtdReso);
466: db.setErrorHandler(dtdReso);
467:
468: // This is the parent XML file into which all the web xml snippets
469: // will be merged into
470: File webXML = new File(commonWebSrc + FS + "WEB-INF" + FS
471: + "xml" + FS + "web.xml");
472: // Parse the
473: Document destDoc = db.parse(new InputSource(
474: new InputStreamReader(new FileInputStream(webXML),
475: "UTF-8")));
476:
477: // Remove the main web.xml file from list of files to be merged.
478: webXMLFiles.remove(webXML);
479:
480: int iWebXMLFilesSize = (webXMLFiles != null) ? webXMLFiles
481: .size() : 0;
482: for (int i = 0; i < iWebXMLFilesSize; i++) {
483: File currXMLFile = (File) webXMLFiles.get(i);
484: FileInputStream currFIS = new FileInputStream(
485: currXMLFile);
486: InputStreamReader currISR = new InputStreamReader(
487: currFIS, "UTF-8");
488:
489: // Parse the XML file
490: logger.log(Level.FINEST, "PSFB_CSPFT0302", currXMLFile
491: .getName());
492: Document doc = db.parse(new InputSource(currISR));
493:
494: NodeList nodeList1 = doc.getChildNodes();
495: int iNodeList1Size = nodeList1.getLength();
496: for (int j = 0; j < iNodeList1Size; j++) {
497: NodeList nodeList2 = nodeList1.item(j)
498: .getChildNodes();
499: int iNodeList2Size = nodeList2.getLength();
500: for (int k = 0; k < iNodeList2Size; k++) {
501: mergeNodesIntoParentDoc(destDoc, nodeList2
502: .item(k));
503: }
504: }
505: }
506:
507: NodeList nodeList1 = destDoc.getChildNodes();
508: int iNodeList1Size = nodeList1.getLength();
509: for (int i = 0; i < iNodeList1Size; i++) {
510: NodeList nodeList2 = nodeList1.item(i).getChildNodes();
511: int iNodeList2Size = nodeList2.getLength();
512: for (int j = 0; j < iNodeList2Size; j++) {
513: Node testNode = nodeList2.item(j);
514: if (testNode instanceof Element
515: && !testNode.hasChildNodes()) {
516: destDoc.getDocumentElement().removeChild(
517: testNode);
518: }
519: }
520: }
521:
522: // Get the doc type for the web.xml
523: DocumentType doctype = destDoc.getDoctype();
524: Transformer t = TransformerFactory.newInstance()
525: .newTransformer();
526: t.setOutputProperty(OutputKeys.INDENT, "yes");
527: t.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
528: DOCTYPE_PUBLIC);
529: t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
530: DOCTYPE_SYSTEM);
531:
532: DOMSource ds = new DOMSource(destDoc);
533: StringWriter sw = new StringWriter();
534: StreamResult sr = new StreamResult(sw);
535: t.transform(ds, sr);
536:
537: //Create output stream and write merged web xmls to file
538: FileOutputStream xmlOutStream = new FileOutputStream(
539: mergedWebXMLFile);
540: xmlOutStream.write(sw.getBuffer().toString().getBytes(
541: "UTF-8"));
542: xmlOutStream.flush();
543: xmlOutStream.close();
544:
545: } catch (Exception e) {
546: logger.log(Level.SEVERE, "PSFB_CSPFT0303", e);
547: }
548: }
549:
550: private void mergeNodesIntoParentDoc(Document destDoc, Node node) {
551: boolean found = false;
552: if (node instanceof Element) {
553: String sNodeName = node.getNodeName();
554: NodeList nodeList1 = destDoc.getChildNodes();
555: int iNodeList1Size = nodeList1.getLength();
556: for (int i = 0; i < iNodeList1Size; i++) {
557: NodeList nodeList2 = nodeList1.item(i).getChildNodes();
558: int iNodeList2Size = nodeList2.getLength();
559: for (int j = 0; j < iNodeList2Size; j++) {
560: Node testNode = nodeList2.item(j);
561: if (testNode.getNodeName().equals(sNodeName)) {
562: found = true;
563: } else if (found == true) {
564: destDoc.getDocumentElement().insertBefore(
565: destDoc.importNode(node, true),
566: testNode);
567: return;
568: }
569: }
570: }
571: }
572: if (found == true) {
573: destDoc.getDocumentElement().insertBefore(
574: destDoc.importNode(node, true), null);
575: }
576: }
577: }
|