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.modules.tomcat5.ide;
043:
044: import java.io.BufferedInputStream;
045: import java.io.BufferedOutputStream;
046: import java.io.File;
047: import java.io.FileInputStream;
048: import java.io.FileOutputStream;
049: import java.io.IOException;
050: import java.io.OutputStream;
051: import java.net.URL;
052: import java.util.logging.Level;
053: import java.util.logging.Logger;
054: import org.netbeans.modules.j2ee.dd.api.web.DDProvider;
055: import org.netbeans.modules.j2ee.dd.api.web.Filter;
056: import org.netbeans.modules.j2ee.dd.api.web.FilterMapping;
057: import org.netbeans.modules.j2ee.dd.api.common.InitParam;
058: import org.netbeans.modules.j2ee.dd.api.web.WebApp;
059: import org.netbeans.modules.j2ee.deployment.plugins.api.InstanceProperties;
060: import org.netbeans.modules.tomcat5.TomcatManager;
061: import org.openide.modules.ModuleInfo;
062: import org.openide.util.Lookup;
063: import org.openide.util.LookupListener;
064: import org.openide.util.LookupEvent;
065:
066: import org.openide.modules.InstalledFileLocator;
067: import org.xml.sax.SAXException;
068:
069: import org.netbeans.modules.schema2beans.Common;
070: import org.netbeans.modules.schema2beans.BaseBean;
071: import org.openide.filesystems.FileObject;
072: import org.openide.filesystems.FileSystem;
073: import org.openide.filesystems.Repository;
074: import org.openide.filesystems.URLMapper;
075:
076: /** Monitor enabling/disabling utilities for Tomcat 5.
077: *
078: * @author Milan.Kuchtiak@sun.com, Petr Jiricka
079: */
080: public class MonitorSupport {
081:
082: private static final Logger LOGGER = Logger
083: .getLogger(MonitorSupport.class.getName());
084:
085: // monitor module enable status data
086: public static final String MONITOR_ENABLED_PROPERTY_NAME = "monitor_enabled"; // NOI18N
087: private static final String MONITOR_MODULE_NAME = "org.netbeans.modules.web.monitor"; //NOI18N
088: private static ModuleInfo httpMonitorInfo;
089: private static ModuleSpy monitorSpy;
090: private static Lookup.Result res;
091: private static MonitorInfoListener monitorInfoListener;
092: private static MonitorLookupListener monitorLookupListener;
093:
094: // data for declaration in web.xml
095: private static final String MONITOR_FILTER_NAME = "HTTPMonitorFilter"; //NOI18N
096: private static final String MONITOR_FILTER_CLASS = "org.netbeans.modules.web.monitor.server.MonitorFilter"; //NOI18N
097: private static final String MONITOR_FILTER_PATTERN = "/*"; //NOI18N
098: private static final String MONITOR_INTERNALPORT_PARAM_NAME = "netbeans.monitor.ide"; //NOI18N
099:
100: public static void setMonitorFlag(String managerURL, boolean enable) {
101: InstanceProperties ip = InstanceProperties
102: .getInstanceProperties(managerURL);
103: ip.setProperty(MONITOR_ENABLED_PROPERTY_NAME, Boolean
104: .toString(enable));
105: }
106:
107: public static boolean getMonitorFlag(String managerURL) {
108: InstanceProperties ip = InstanceProperties
109: .getInstanceProperties(managerURL);
110: String prop = ip.getProperty(MONITOR_ENABLED_PROPERTY_NAME);
111: return (prop == null) ? true : Boolean.valueOf(prop)
112: .booleanValue();
113: }
114:
115: public static void setMonitorFlag(TomcatManager tm, boolean enable) {
116: setMonitorFlag(tm.getUri(), enable);
117: }
118:
119: public static boolean getMonitorFlag(TomcatManager tm) {
120: return getMonitorFlag(tm.getUri());
121: }
122:
123: public static void synchronizeMonitorWithFlag(TomcatManager tm,
124: boolean alsoSetPort) throws IOException, SAXException {
125: String url = tm.getUri();
126: boolean monitorFlag = getMonitorFlag(url);
127: boolean monitorModuleAvailable = isMonitorEnabled();
128: boolean shouldInstall = monitorModuleAvailable && monitorFlag;
129:
130: // find the web.xml file
131: File webXML = getDefaultWebXML(tm);
132: if (webXML == null) {
133: Logger.getLogger(MonitorSupport.class.getName()).log(
134: Level.INFO, null, new Exception(url));
135: return;
136: }
137: WebApp webApp = DDProvider.getDefault().getDDRoot(webXML);
138: if (webApp == null) {
139: Logger.getLogger(MonitorSupport.class.getName()).log(
140: Level.INFO, null, new Exception(url));
141: return;
142: }
143: boolean needsSave = false;
144: boolean result;
145: if (shouldInstall) {
146: addMonitorJars(tm);
147: result = changeFilterMonitor(webApp, true);
148: needsSave = needsSave || result;
149: if (alsoSetPort) {
150: result = specifyFilterPortParameter(webApp);
151: needsSave = needsSave || result;
152: }
153: } else {
154: result = changeFilterMonitor(webApp, false);
155: needsSave = needsSave || result;
156: }
157: if (needsSave) {
158: OutputStream os = new FileOutputStream(webXML);
159: try {
160: webApp.write(os);
161: } finally {
162: os.close();
163: }
164: }
165: }
166:
167: private static File getDefaultWebXML(TomcatManager tm) {
168: File cb = tm.getTomcatProperties().getCatalinaDir();
169: File webXML = new File(cb, "conf" + File.separator + "web.xml");
170: if (webXML.exists())
171: return webXML;
172: return null;
173: }
174:
175: private static void addMonitorJars(TomcatManager tm)
176: throws IOException {
177: // getting Tomcat4.0 Directory
178: File instDir = tm.getTomcatProperties().getCatalinaHome();
179: if (instDir == null)
180: return;
181: File libFolder = tm.getTomcatProperties().getMonitorLibFolder();
182: copyFromIDEInstToDir(
183: "modules/ext/org-netbeans-modules-web-httpmonitor.jar",
184: new File(libFolder,
185: "org-netbeans-modules-web-httpmonitor.jar")); // NOI18N
186: copyFromIDEInstToDir(
187: "modules/org-netbeans-modules-schema2beans.jar",
188: new File(libFolder,
189: "org-netbeans-modules-schema2beans.jar")); // NOI18N
190:
191: //copyFromIDEInstToDir("modules/ext/monitor-valve.jar", instDir, "server/lib/monitor-valve.jar"); // NOI18N
192: }
193:
194: private static boolean changeFilterMonitor(WebApp webApp,
195: boolean full) {
196: boolean filterWasChanged = false;
197: if (full) { // adding monitor filter/filter-mapping element
198: //if (tomcat.isMonitorEnabled()) {
199: boolean isFilter = false;
200: Filter[] filters = webApp.getFilter();
201: for (int i = 0; i < filters.length; i++) {
202: if (filters[i].getFilterName().equals(
203: MONITOR_FILTER_NAME)) {
204: isFilter = true;
205: break;
206: }
207: }
208: if (!isFilter) {
209: try {
210: Filter filter = (Filter) webApp
211: .createBean("Filter"); //NOI18N
212: filter.setFilterName(MONITOR_FILTER_NAME);
213: filter.setFilterClass(MONITOR_FILTER_CLASS);
214: /* InitParam initParam = (InitParam)filter.createBean("InitParam"); //NOI18N
215: initParam.setParamName(MONITOR_INIT_PARAM_NAME);
216: initParam.setParamValue(MONITOR_INIT_PARAM_VALUE);
217: filter.addInitParam(initParam);*/
218: webApp.addFilter(filter);
219: filterWasChanged = true;
220: } catch (ClassNotFoundException ex) {
221: }
222: }
223:
224: boolean isMapping = false;
225: FilterMapping[] maps = webApp.getFilterMapping();
226: for (int i = 0; i < maps.length; i++) {
227: if (maps[i].getFilterName().equals(MONITOR_FILTER_NAME)) {
228: isMapping = true;
229: break;
230: }
231: }
232: if (!isMapping) {
233: try {
234: FilterMapping filterMapping = (FilterMapping) webApp
235: .createBean("FilterMapping"); //NOI18N
236:
237: // setting the dispatcher values even for Servlet2.3 web.xml
238: String[] dispatcher = new String[] { "REQUEST",
239: "FORWARD", "INCLUDE", "ERROR" }; //NOI18N
240: try {
241: filterMapping.setDispatcher(dispatcher);
242: } catch (org.netbeans.modules.j2ee.dd.api.common.VersionNotSupportedException ex) {
243: ((BaseBean) filterMapping).createProperty(
244: "dispatcher", // NOI18N
245: "Dispatcher", // NOI18N
246: Common.TYPE_0_N | Common.TYPE_STRING
247: | Common.TYPE_KEY,
248: java.lang.String.class);
249: ((BaseBean) filterMapping).setValue(
250: "Dispatcher", dispatcher); // NOI18N
251: }
252:
253: filterMapping.setFilterName(MONITOR_FILTER_NAME);
254: filterMapping.setUrlPattern(MONITOR_FILTER_PATTERN);
255: webApp.addFilterMapping(filterMapping);
256: filterWasChanged = true;
257: } catch (ClassNotFoundException ex) {
258: }
259: }
260: //}
261: } else { // removing monitor filter/filter-mapping element
262: FilterMapping[] maps = webApp.getFilterMapping();
263: for (int i = 0; i < maps.length; i++) {
264:
265: if (maps[i].getFilterName().equals(MONITOR_FILTER_NAME)) {
266: webApp.removeFilterMapping(maps[i]);
267: filterWasChanged = true;
268: break;
269: }
270: }
271: Filter[] filters = webApp.getFilter();
272: for (int i = 0; i < filters.length; i++) {
273: if (filters[i].getFilterName().equals(
274: MONITOR_FILTER_NAME)) {
275: webApp.removeFilter(filters[i]);
276: filterWasChanged = true;
277: break;
278: }
279: }
280: }
281: return filterWasChanged;
282: }
283:
284: /** Finds a file inside the IDE installation, given a slash-separated
285: * path relative to the IDE installation. Takes into account the fact that
286: * modules may have been installed by Autoupdate, and reside in the user
287: * home directory.
288: * @param instRelPath file path relative to the inst dir, delimited by '/'
289: * @return file containing the file, or null if it does not exist.
290: */
291: private static File findInstallationFile(String instRelPath) {
292: return InstalledFileLocator.getDefault().locate(instRelPath,
293: null, false);
294: }
295:
296: private static void copyFromIDEInstToDir(String sourceRelPath,
297: File targetFile) throws IOException {
298: File sourceFile = findInstallationFile(sourceRelPath);
299: if (sourceFile != null && sourceFile.exists()) {
300: if (!targetFile.exists()
301: || sourceFile.length() != targetFile.length()) {
302: copy(sourceFile, targetFile);
303: }
304: }
305: }
306:
307: private static void copy(File file1, File file2) throws IOException {
308: BufferedInputStream bis = new BufferedInputStream(
309: new FileInputStream(file1));
310: BufferedOutputStream bos = new BufferedOutputStream(
311: new FileOutputStream(file2));
312: int b;
313: while ((b = bis.read()) != -1)
314: bos.write(b);
315: bis.close();
316: bos.close();
317: }
318:
319: /** Inserts or and updates in the Monitor Filter element the parameter
320: * which tells the Monitor the number of the internal port,
321: * depending on whether the integration mode is full or minimal
322: * @param webApp deployment descriptor in which to do the changes
323: * @return true if the default deployment descriptor was modified
324: */
325: private static boolean specifyFilterPortParameter(WebApp webApp) {
326: Filter[] filters = webApp.getFilter();
327: Filter myFilter = null;
328: for (int i = 0; i < filters.length; i++) {
329: if (MONITOR_FILTER_NAME.equals(filters[i].getFilterName())) {
330: myFilter = filters[i];
331: break;
332: }
333: }
334: // see if we found it
335: if (myFilter == null)
336: return false;
337:
338: // look for the parameter
339: InitParam[] params = myFilter.getInitParam();
340: InitParam myParam = null;
341: for (int i = 0; i < params.length; i++) {
342: if (MONITOR_INTERNALPORT_PARAM_NAME.equals(params[i]
343: .getParamName())) {
344: myParam = params[i];
345: break;
346: }
347: }
348:
349: // host name acts as the parameter name
350: String correctParamValue = getLocalHost() + ":"
351: + getInternalServerPort(); // NOI18N
352:
353: // insert or correct the param
354: if (myParam == null) {
355: // add it
356: try {
357: InitParam init = (InitParam) myFilter
358: .createBean("InitParam"); //NOI18N
359: init.setParamName(MONITOR_INTERNALPORT_PARAM_NAME);
360: init.setParamValue(correctParamValue);
361: myFilter.addInitParam(init);
362: } catch (ClassNotFoundException ex) {
363: LOGGER.log(Level.FINE, null, ex);
364: }
365: return true;
366: } else {
367: // check whether the value is correct
368: if (correctParamValue.equals(myParam.getParamValue())) {
369: // no need to change
370: return false;
371: } else {
372: // change
373: myParam.setParamValue(correctParamValue);
374: return true;
375: }
376: }
377:
378: } // end of specifyFilterPortParameter
379:
380: public static String getLocalHost() {
381: // just return 127.0.0.1, other values don't seem to work reliably
382: return "127.0.0.1"; // NOI18N
383: /**
384: try {
385: return InetAddress.getLocalHost().getHostName();
386: }
387: catch (UnknownHostException e) {
388: return "127.0.0.1"; // NOI18N
389: }
390: */
391: }
392:
393: private static URL getSampleHTTPServerURL() {
394: FileSystem fs = Repository.getDefault().getDefaultFileSystem();
395: FileObject fo = fs.findResource("HTTPServer_DUMMY");
396: if (fo == null) {
397: return null;
398: }
399: URL u = URLMapper.findURL(fo, URLMapper.NETWORK);
400: return u;
401: }
402:
403: private static String getInternalServerPort() {
404: //URL u = HttpServer.getRepositoryRoot();
405: URL u = getSampleHTTPServerURL();
406: if (u != null) {
407: return "" + u.getPort(); // NOI18N
408: } else {
409: return "8082"; // NOI18N
410: }
411: }
412:
413: /* private void manageConfiguration(){
414: Tomcat40DataObject tdo = getTomcatDataObject();
415: boolean monitorEnabled = Tomcat40WebServer.getServer().isMonitorEnabled();
416: boolean ideMode = tdo.isIdeMode();
417: FileObject fo = tdo.getPrimaryFile();
418: Boolean monitorFilter = (Boolean)fo.getAttribute(Tomcat40DataObject.MONITOR_FILTER_ATTRIBUTE);
419: if (ideMode) {
420:
421: // add compilation stuff
422: tdo.addCompilationJar();
423:
424: if (monitorEnabled) {
425: if (!Boolean.TRUE.equals(monitorFilter)) {
426: // monitor filter need to be added
427: DDDataObject dd = tdo.getDD();
428: if (dd==null) return;
429: WebApp webApp = dd.getWebApp();
430: if (webApp==null) return;
431: if (tdo.changeFilterMonitor(webApp, true)) dd.setNodeDirty(true);
432: }
433: // also need to add the monitor jars
434: // all this code should be redesigned, so the following line should only be consodered temporary
435: tdo.addMonitorJars();
436: }
437: if (!monitorEnabled && !Boolean.FALSE.equals(monitorFilter)) {
438: // monitor filter need to be deleted
439: DDDataObject dd = tdo.getDD();
440: if (dd==null) return;
441: WebApp webApp = dd.getWebApp();
442: if (webApp==null) return;
443: if (tdo.changeFilterMonitor(webApp, false)) dd.setNodeDirty(true);
444: tdo.removeAllMonitorValves();
445: }
446: }
447:
448: // pointbase stuff
449: tdo.addPointbaseJar();
450:
451: DDDataObject dd = tdo.getDD();
452: if (dd==null) return;
453: WebApp webApp = dd.getWebApp();
454: if (webApp==null) return;
455: if (tdo.specifyIDEServletParameter(webApp)) {
456: dd.setNodeDirty(true);
457: }
458: if (tdo.specifyFilterPortParameter(webApp)) {
459: dd.setNodeDirty(true);
460: }
461: }
462: */
463:
464: private static void startModuleSpy(final ModuleSpy spy) {
465: // trying to hang a listener on monitor module
466: res = Lookup.getDefault().lookup(
467: new Lookup.Template(ModuleInfo.class));
468: java.util.Iterator it = res.allInstances().iterator();
469: final String moduleId = spy.getModuleId();
470: boolean found = false;
471: while (it.hasNext()) {
472: org.openide.modules.ModuleInfo mi = (ModuleInfo) it.next();
473: if (mi.getCodeName().startsWith(moduleId)) {
474: httpMonitorInfo = mi;
475: spy.setEnabled(mi.isEnabled());
476: monitorInfoListener = new MonitorInfoListener(spy);
477: httpMonitorInfo
478: .addPropertyChangeListener(monitorInfoListener);
479: found = true;
480: break;
481: }
482: }
483: // hanging a listener to the lookup result
484: monitorLookupListener = new MonitorLookupListener(spy,
485: httpMonitorInfo);
486: res.addLookupListener(monitorLookupListener);
487: }
488:
489: private static class ModuleSpy {
490: private boolean enabled;
491: private String moduleId;
492:
493: public ModuleSpy(String moduleId) {
494: this .moduleId = moduleId;
495: }
496:
497: public void setModuleId(String moduleId) {
498: this .moduleId = moduleId;
499: }
500:
501: public void setEnabled(boolean enabled) {
502: this .enabled = enabled;
503: }
504:
505: public boolean isEnabled() {
506: return enabled;
507: }
508:
509: public String getModuleId() {
510: return moduleId;
511: }
512: }
513:
514: static synchronized boolean isMonitorEnabled() {
515: if (monitorSpy == null) {
516: monitorSpy = new ModuleSpy(MONITOR_MODULE_NAME);
517: startModuleSpy(monitorSpy);
518: }
519: return monitorSpy.isEnabled();
520: }
521:
522: // PENDING - who should call this?
523: void removeListeners() {
524: if (httpMonitorInfo != null) {
525: httpMonitorInfo
526: .removePropertyChangeListener(monitorInfoListener);
527: }
528: if (res != null) {
529: res.removeLookupListener(monitorLookupListener);
530: }
531: }
532:
533: private static class MonitorInfoListener implements
534: java.beans.PropertyChangeListener {
535: ModuleSpy spy;
536:
537: MonitorInfoListener(ModuleSpy spy) {
538: this .spy = spy;
539: }
540:
541: public void propertyChange(java.beans.PropertyChangeEvent evt) {
542: if (evt.getPropertyName().equals("enabled")) { // NOI18N
543: spy.setEnabled(((Boolean) evt.getNewValue())
544: .booleanValue());
545: }
546: }
547: }
548:
549: private static class MonitorLookupListener implements
550: LookupListener {
551:
552: ModuleSpy spy;
553: ModuleInfo httpMonitorInfo;
554:
555: MonitorLookupListener(ModuleSpy spy, ModuleInfo httpMonitorInfo) {
556: this .spy = spy;
557: this .httpMonitorInfo = httpMonitorInfo;
558: }
559:
560: public void resultChanged(LookupEvent lookupEvent) {
561: java.util.Iterator it = res.allInstances().iterator();
562: boolean moduleFound = false;
563: while (it.hasNext()) {
564: ModuleInfo mi = (ModuleInfo) it.next();
565: if (mi.getCodeName().startsWith(spy.getModuleId())) {
566: spy.setEnabled(mi.isEnabled());
567: if (httpMonitorInfo == null) {
568: httpMonitorInfo = mi;
569: monitorInfoListener = new MonitorInfoListener(
570: spy);
571: httpMonitorInfo
572: .addPropertyChangeListener(monitorInfoListener);
573: }
574: moduleFound = true;
575: break;
576: }
577: }
578: if (!moduleFound) {
579: if (httpMonitorInfo != null) {
580: httpMonitorInfo
581: .removePropertyChangeListener(monitorInfoListener);
582: httpMonitorInfo = null;
583: spy.setEnabled(false);
584: }
585: }
586: }
587:
588: }
589: }
|