001: /*
002: * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
003: * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to license terms.
004: */
005:
006: package com.sun.portal.ffj.util;
007:
008: import java.util.Iterator;
009: import java.util.StringTokenizer;
010: import java.util.Properties;
011: import java.util.TreeSet;
012:
013: import java.net.URL;
014: import java.net.URLEncoder;
015:
016: import java.io.File;
017: import java.io.IOException;
018: import java.io.InputStreamReader;
019: import java.io.InputStream;
020: import java.io.FileInputStream;
021: import java.io.BufferedReader;
022: import java.io.PrintWriter;
023: import java.io.FileWriter;
024: import java.io.OutputStream;
025: import java.io.FileOutputStream;
026: import java.io.ObjectOutputStream;
027: import java.io.PrintWriter;
028:
029: import org.xml.sax.InputSource;
030: import org.xml.sax.SAXException;
031:
032: import org.w3c.dom.Document;
033: import org.w3c.dom.Element;
034: import org.w3c.dom.Comment;
035: import org.w3c.dom.Node;
036: import org.w3c.dom.NodeList;
037:
038: import org.openide.TopManager;
039: import org.openide.ErrorManager;
040:
041: import org.openide.xml.XMLUtil;
042:
043: import org.openide.filesystems.Repository;
044: import org.openide.filesystems.FileObject;
045: import org.openide.filesystems.FileSystem;
046: import org.openide.filesystems.FileStateInvalidException;
047: import org.openide.filesystems.FileUtil;
048:
049: import org.openide.cookies.CompilerCookie;
050:
051: import org.openide.compiler.CompilerJob;
052: import org.openide.compiler.Compiler;
053: import org.openide.compiler.CompilerTask;
054:
055: import org.openide.util.NbBundle;
056:
057: import org.openide.loaders.DataObject;
058: import org.openide.loaders.DataObjectNotFoundException;
059:
060: import org.netbeans.modules.web.config.WebAppDescriptor;
061:
062: import com.sun.portal.portlet.cli.PDWebAppUpdater;
063:
064: // FIXME - the methods used from these should be moved into "util" and
065: // shared.
066:
067: import com.sun.portal.ffj.filesystems.PSFileSystem;
068: import com.sun.portal.ffj.filesystems.PSFSInstall;
069:
070: public class PortletWebInf implements PSConstants {
071: public PortletWebInf(File winf) {
072: m_WebInf = winf;
073: }
074:
075: public void create() throws IOException {
076: File classdir = new File(m_WebInf, "classes");
077: classdir.mkdirs();
078: File libdir = new File(m_WebInf, "lib");
079: libdir.mkdirs();
080:
081: // Get default filesystem from layer XML.
082:
083: Repository repo = TopManager.getDefault().getRepository();
084: FileSystem defaultFS = repo.getDefaultFileSystem();
085:
086: FileObject fromtop = defaultFS
087: .find(PORTLET_WEB_INF, null, null);
088: FileObject fromlib = defaultFS.find(PORTLET_WEB_INF + ".lib",
089: null, null);
090:
091: int ifex = FileOverwriteDialog.SKIP;
092: ifex = copyChildren(fromtop, m_WebInf, ifex);
093: copyChildren(fromlib, libdir, ifex);
094: createTestJSP();
095: fixPDConfig();
096: fixTomcatContexts();
097: }
098:
099: public void prewar(FileObject ddfob, FileObject pafob)
100: throws Exception {
101: File libdir = new File(m_WebInf, "lib");
102:
103: Repository repo = TopManager.getDefault().getRepository();
104: FileSystem defaultFS = repo.getDefaultFileSystem();
105:
106: FileObject fromlib = defaultFS.find(PORTLET_WEB_INF + ".lib",
107: null, null);
108:
109: removeChildren(fromlib, libdir);
110: File webxml = new File(m_WebInf, "web.xml");
111: File saveweb = new File(m_WebInf, "saveweb.xml");
112: saveweb.delete();
113: webxml.renameTo(saveweb);
114: File tfile = PDWebAppUpdater.removeWebAppParam(
115: new FileInputStream(saveweb), getPDConfigProps());
116: textCopy(tfile, webxml);
117: synchPortlets(ddfob, pafob);
118: }
119:
120: public void postwar(FileObject ddfob) throws IOException {
121: File libdir = new File(m_WebInf, "lib");
122:
123: Repository repo = TopManager.getDefault().getRepository();
124: FileSystem defaultFS = repo.getDefaultFileSystem();
125:
126: FileObject fromlib = defaultFS.find(PORTLET_WEB_INF + ".lib",
127: null, null);
128:
129: copyChildren(fromlib, libdir, FileOverwriteDialog.SKIP_ALL);
130:
131: File webxml = new File(m_WebInf, "web.xml");
132: File saveweb = new File(m_WebInf, "saveweb.xml");
133: webxml.delete();
134: saveweb.renameTo(webxml);
135: }
136:
137: public void prepareExec(FileObject ddfob, FileObject pafob)
138: throws Exception {
139: File libdir = new File(m_WebInf, "lib");
140:
141: Repository repo = TopManager.getDefault().getRepository();
142: FileSystem defaultFS = repo.getDefaultFileSystem();
143:
144: FileObject winfobj = ddfob.getParent();
145: FileObject winfch[] = winfobj.getChildren();
146: for (int i = 0; i < winfch.length; ++i) {
147: if (winfch[i].getNameExt().equals(
148: PORTLET_WEBGROUP_NAME + "." + PORTLET_WEBGROUP_EXT)) {
149: winfobj.getParent().setAttribute("NbAttrWebApp",
150: winfch[i]);
151: PSFileSystem psFS = (PSFileSystem) PSFileSystem
152: .getPSFilesystem(true);
153: FileSystem fs = winfobj.getFileSystem();
154: WebAppDescriptor portlet = new WebAppDescriptor(fs
155: .getSystemName(), PORTLET_MAP_NAME);
156: WebAppDescriptor psfs = new WebAppDescriptor(psFS
157: .getDisplayName(), PSFS_MAP_NAME);
158: TreeSet ts = new TreeSet();
159: ts.add(portlet);
160: ts.add(psfs);
161: File grp = FileUtil.toFile(winfch[i]);
162: ObjectOutputStream os = new ObjectOutputStream(
163: new FileOutputStream(grp));
164: os.writeObject(ts);
165: os.flush();
166: os.close();
167: winfch[i].refresh();
168: break;
169: }
170: }
171:
172: FileObject fromlib = defaultFS.find(PORTLET_WEB_INF + ".lib",
173: null, null);
174: copyChildren(fromlib, libdir, FileOverwriteDialog.SKIP_ALL);
175: synchPortlets(ddfob, pafob);
176: }
177:
178: public FileObject getTestJSP(FileObject ddfob)
179: throws FileStateInvalidException {
180: FileSystem fs = ddfob.getFileSystem();
181: return fs.findResource(PORTLET_TEST_JSP);
182: }
183:
184: private Properties getPDConfigProps() throws Exception {
185: Properties props = new Properties();
186: File f = new File(m_WebInf, PDCONFIG_FILE);
187: props.load(new FileInputStream(f));
188: return props;
189: }
190:
191: private void synchPortlets(FileObject ddfob, FileObject pafob)
192: throws Exception {
193:
194: Node refChild = null;
195: Node firstChild = null;
196: Document doc = descriptorDoc();
197: Element top = doc.getDocumentElement();
198: NodeList kids = top.getChildNodes();
199:
200: for (int i = 0; i < kids.getLength(); ++i) {
201: Node nd = kids.item(i);
202:
203: // remove any existing portlet elements.
204:
205: if (nd instanceof Element) {
206: if (nd.getNodeName().equals("portlet")) {
207: top.removeChild(nd);
208: continue;
209: }
210:
211: // If we encounter an element, we want to insert the portlets before it.
212:
213: if (refChild == null) {
214: refChild = nd;
215: }
216: continue;
217: }
218:
219: if (refChild != null) {
220: continue;
221: }
222:
223: // Logic to set refChild to node immediately AFTER expected leading
224: // comment, which at least initially, tells them not to insert portlets.
225:
226: if (nd instanceof Comment) {
227: if (firstChild == null) {
228: firstChild = nd;
229: continue;
230: }
231: refChild = nd;
232: }
233: }
234:
235: File classdir = new File(m_WebInf, "classes");
236: PortletList pl = new PortletList(classdir);
237: Object aobj = pafob.getAttribute(PORTLET_SET_PROPERTY);
238: String list = aobj == null ? null : aobj.toString();
239: Iterator it = null;
240: if (list == null || list.equals(ALL_PORTLETS)) {
241: it = pl.portletClasses();
242: } else {
243: it = new EnumerationIterator(new StringTokenizer(list,
244: PORTLET_LIST_DELIM));
245: }
246:
247: while (it.hasNext()) {
248: String cls = (String) it.next();
249: Element elt = pl.portletElement(cls);
250: if (elt != null) {
251: Node nd = doc.importNode(elt, true);
252: top.insertBefore(nd, refChild);
253: }
254: compilePortlet(ddfob.getFileSystem(), cls);
255: }
256:
257: File dd = new File(m_WebInf, PORTLET_DESCRIPTOR_FILE);
258: XMLUtil.write(doc, new FileOutputStream(dd), "UTF-8");
259: }
260:
261: private Document descriptorDoc() throws Exception {
262:
263: File dd = new File(m_WebInf, PORTLET_DESCRIPTOR_FILE);
264: return XMLUtil.parse(new InputSource(new FileInputStream(dd)),
265: false, false, null, null);
266: }
267:
268: private void compilePortlet(FileSystem fs, String cls) {
269:
270: int idx = cls.lastIndexOf('.');
271: String name = cls;
272: if (idx > 0) {
273: name = cls.substring(idx + 1);
274: cls = "WEB-INF.classes." + cls.substring(0, idx);
275: } else {
276: cls = "WEB-INF.classes";
277: }
278:
279: FileObject fobj = fs.find(cls, name, "java");
280: if (fobj != null) {
281: try {
282: CompilerCookie cc = (CompilerCookie) DataObject.find(
283: fobj).getCookie(CompilerCookie.Compile.class);
284: if (cc != null) {
285: CompilerJob cjob = new CompilerJob(
286: Compiler.DEPTH_ONE);
287: cc.addToJob(cjob, Compiler.DEPTH_ONE);
288: CompilerTask tsk = cjob.start();
289: tsk.waitFinished();
290: }
291: } catch (DataObjectNotFoundException donfe) {
292: TopManager.getDefault().getErrorManager().notify(
293: ErrorManager.USER, donfe);
294: }
295: }
296: }
297:
298: private int copyChildren(FileObject from, File todir, int ifex)
299: throws IOException {
300: FileObject ch[] = from.getChildren();
301: for (int i = 0; i < ch.length; ++i) {
302: if (ch[i].isFolder()) {
303: continue;
304: }
305:
306: // Create new file. For text types, use a reader and copy with a
307: // printwriter to conform to local filesystem notion of a newline.
308: // Currently, we recognize "jar" as a binary type.
309:
310: String nm = ch[i].getNameExt();
311: File to = new File(todir, nm);
312:
313: if (to.exists()) {
314: if (ifex != FileOverwriteDialog.SKIP_ALL
315: && ifex != FileOverwriteDialog.OVERWRITE_ALL) {
316: FileOverwriteDialog fod = new FileOverwriteDialog(
317: null, true, todir.getPath(), nm, ifex);
318: fod.show();
319: ifex = fod.getOverwriteChoice();
320: }
321: if (ifex == FileOverwriteDialog.SKIP
322: || ifex == FileOverwriteDialog.SKIP_ALL) {
323: continue;
324: }
325: }
326:
327: URL url = ch[i].getURL();
328: String ext = ch[i].getExt();
329:
330: if (ext.equals("jar")) {
331: binaryCopy(url, to);
332: } else {
333: textCopy(url, to);
334: }
335: }
336:
337: return ifex;
338: }
339:
340: private void textCopy(URL url, File to) throws IOException {
341:
342: InputStreamReader isr = new InputStreamReader((InputStream) url
343: .getContent());
344: BufferedReader br = new BufferedReader(isr);
345: PrintWriter pw = new PrintWriter(new FileWriter(to));
346:
347: for (;;) {
348: String s = br.readLine();
349: if (s == null)
350: break;
351: pw.println(s);
352: }
353:
354: pw.flush();
355: pw.close();
356: }
357:
358: private void textCopy(File from, File to) throws IOException {
359:
360: InputStreamReader isr = new InputStreamReader(
361: new FileInputStream(from));
362: BufferedReader br = new BufferedReader(isr);
363: PrintWriter pw = new PrintWriter(new FileWriter(to));
364:
365: for (;;) {
366: String s = br.readLine();
367: if (s == null)
368: break;
369: pw.println(s);
370: }
371:
372: pw.flush();
373: pw.close();
374: }
375:
376: private void binaryCopy(URL url, File to) throws IOException {
377:
378: InputStream is = (InputStream) url.getContent();
379: OutputStream os = new FileOutputStream(to);
380:
381: byte buf[] = new byte[2400];
382: int len;
383: while ((len = is.read(buf)) > 0) {
384: os.write(buf, 0, len);
385: }
386:
387: os.flush();
388: os.close();
389: }
390:
391: private void removeChildren(FileObject from, File todir) {
392: FileObject ch[] = from.getChildren();
393: for (int i = 0; i < ch.length; ++i) {
394: if (ch[i].isFolder()) {
395: continue;
396: }
397:
398: File to = new File(todir, ch[i].getNameExt());
399:
400: if (to.exists()) {
401: to.delete();
402: continue;
403: }
404: }
405: }
406:
407: // The jsp is so short, and there is so much syntax to be substituted, that we
408: // just write it programmatically. We also create the Portlet app control file at
409: // this point.
410:
411: public void createTestJSP() throws IOException {
412: File jsp = new File(m_WebInf.getParentFile(), PORTLET_TEST_JSP);
413: PrintWriter pw = new PrintWriter(new FileOutputStream(jsp));
414: PSFileSystem psFS = (PSFileSystem) PSFileSystem
415: .getPSFilesystem(true);
416: pw.println("<%@page contentType=\"text/html\"%>");
417: pw
418: .println("<%-- This file is required for testing portlet applications. --%>");
419: pw
420: .println("<%-- Should not normally be removed or modified. --%>");
421: pw.println("<%");
422: pw
423: .println(" String unm = request.getParameter(\"USERNAME\");");
424: pw
425: .println(" unm = (unm != null && unm.length() > 0) ? \"&USERNAME=\"+unm : \"\";");
426: StringBuffer red = new StringBuffer();
427: red.append(" String url = \"");
428: red.append(PSFS_MAP_NAME);
429: red.append("/");
430: red.append(PS_SIMULATOR_FILENAME);
431: red.append(".");
432: red.append(PS_SIMULATOR_FILEEXT);
433: red.append("?COMPFILE=");
434: red.append(URLEncoder.encode(PSFSInstall.reverseBS(psFS
435: .getRootDirectory().getPath())));
436: red
437: .append("/desktop/default/HarnessPortletChannel/HarnessPortletProvider.psxml");
438: red.append("&PORTAPPDIR=");
439: red.append(URLEncoder.encode(PSFSInstall.reverseBS(m_WebInf
440: .getParentFile().getPath())));
441: red.append("&CONFIGDIR=");
442: red.append(URLEncoder.encode(PSFSInstall.reverseBS(psFS
443: .getRootDirectory().getPath())));
444: red.append("\";");
445: pw.println(red.toString());
446: pw.println(" response.sendRedirect(url+unm);");
447: pw.println("%>");
448: pw.flush();
449: pw.close();
450:
451: File pctl = new File(m_WebInf.getParentFile(),
452: PORTLET_APP_CONTROL);
453: pw = new PrintWriter(new FileOutputStream(pctl));
454: pw
455: .println("This file is required for testing portlet applications.");
456: pw.println("It should not normally be removed or modified.");
457: pw.flush();
458: pw.close();
459: }
460:
461: private void fixPDConfig() {
462: String from[] = { "$(PSFS)", "$(WS)" };
463: String to[] = new String[from.length];
464: to[0] = PSFSInstall.reverseBS(PSFileSystem.getRootPath());
465: to[1] = PSFSInstall.reverseBS(m_WebInf.getParentFile()
466: .getPath());
467:
468: File pdcf = new File(m_WebInf, PDCONFIG_FILE);
469:
470: PSFSInstall.replace(from, to, pdcf.getPath(), pdcf.getPath());
471: }
472:
473: private void fixTomcatContexts() throws IOException {
474: String userDir = System.getProperty("netbeans.user");
475: File cf = new File(userDir, "tomcat401_base/conf/server.xml");
476: File cfcopy = new File(userDir,
477: "tomcat401_base/conf/server.bak");
478: if (!cf.exists()) {
479: cf = new File(userDir, "jwsdp_base/conf/server.xml");
480: cfcopy = new File(userDir, "jwsdp_base/conf/server.bak");
481: }
482: if (!cf.exists()) {
483: return;
484: }
485:
486: // Map SAXException into an I/O exception
487:
488: try {
489: Document sdoc = XMLUtil.parse(new InputSource(
490: new FileInputStream(cf)), false, false, null, null);
491:
492: if (tomcatHostDescent(sdoc.getDocumentElement())) {
493: cf.renameTo(cfcopy);
494: XMLUtil.write(sdoc, new FileOutputStream(cf), "UTF-8");
495: }
496: } catch (SAXException saxex) {
497: throw new IOException("SAX Parse error: "
498: + saxex.getMessage());
499: }
500: }
501:
502: // returns true if it updated the server.xml.
503:
504: private boolean tomcatHostDescent(Element elt) {
505: if (elt.getNodeName().equals("Host")) {
506: return hostContexts(elt);
507: }
508:
509: boolean ret = false;
510: NodeList kids = elt.getChildNodes();
511:
512: for (int i = 0; i < kids.getLength(); ++i) {
513: Node nd = kids.item(i);
514: if (nd instanceof Element) {
515: if (tomcatHostDescent((Element) nd)) {
516: ret = true;
517: }
518: }
519: }
520:
521: return ret;
522: }
523:
524: // This is what really does the update - assure that we have a /portlet
525: // context and a /portalServer context, and they have crossContext set.
526: // Execution of the portlet app will take care of the rest.
527:
528: private boolean hostContexts(Element elt) {
529:
530: boolean noPortlet = true;
531: boolean noPSFS = true;
532: boolean ret = false;
533:
534: NodeList kids = elt.getChildNodes();
535: for (int i = 0; (noPortlet || noPSFS) && i < kids.getLength(); ++i) {
536: Node nd = kids.item(i);
537: if (nd instanceof Element) {
538: Element chelt = (Element) nd;
539: if (chelt.getNodeName().equals("Context")) {
540: String path = chelt.getAttribute("path");
541: if (path != null) {
542: if (path.equals(PORTLET_MAP_NAME)) {
543: String cc = chelt
544: .getAttribute("crossContext");
545: if (cc == null || !cc.equals("true")) {
546: chelt.setAttribute("crossContext",
547: "true");
548: ret = true;
549: }
550: noPortlet = false;
551: }
552: if (path.equals(PSFS_MAP_NAME)) {
553: String cc = chelt
554: .getAttribute("crossContext");
555: if (cc == null || !cc.equals("true")) {
556: chelt.setAttribute("crossContext",
557: "true");
558: ret = true;
559: }
560: noPSFS = false;
561: }
562: }
563: }
564: }
565: }
566:
567: if (noPortlet) {
568: Element ctx = elt.getOwnerDocument().createElement(
569: "Context");
570: ctx.setAttribute("path", PORTLET_MAP_NAME);
571: ctx.setAttribute("crossContext", "true");
572: ctx.setAttribute("docBase", m_WebInf.getParentFile()
573: .getPath());
574: elt.appendChild(ctx);
575: ret = true;
576: }
577:
578: if (noPSFS) {
579: Element ctx = elt.getOwnerDocument().createElement(
580: "Context");
581: ctx.setAttribute("path", PSFS_MAP_NAME);
582: ctx.setAttribute("crossContext", "true");
583: ctx.setAttribute("docBase", PSFileSystem.getRootPath());
584: elt.appendChild(ctx);
585: ret = true;
586: }
587:
588: return ret;
589: }
590:
591: private File m_WebInf;
592:
593: private static final String PDCONFIG_FILE = "PDConfig.properties";
594: }
|