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: * The Original Software is NetBeans. The Initial Developer of the Original
026: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
027: * Microsystems, Inc. All Rights Reserved.
028: *
029: * If you wish your version of this file to be governed by only the CDDL
030: * or only the GPL Version 2, indicate your decision by adding
031: * "[Contributor] elects to include this software in this distribution
032: * under the [CDDL or GPL Version 2] license." If you do not indicate a
033: * single choice of license, a recipient has the option to distribute
034: * your version of this file under either the CDDL, the GPL Version 2 or
035: * to extend the choice of license to its licensees as provided above.
036: * However, if you add GPL Version 2 code and therefore, elected the GPL
037: * Version 2 license, then the option applies only if the new code is
038: * made subject to such option by the copyright holder.
039: */
040:
041: package org.netbeans.modules.profiler.utils;
042:
043: import org.netbeans.api.java.platform.JavaPlatform;
044: import org.netbeans.api.java.platform.JavaPlatformManager;
045: import org.netbeans.api.progress.ProgressHandle;
046: import org.netbeans.api.progress.ProgressHandleFactory;
047: import org.netbeans.api.project.Project;
048: import org.netbeans.api.project.ProjectManager;
049: import org.netbeans.lib.profiler.ProfilerLogger;
050: import org.netbeans.lib.profiler.common.Profiler;
051: import org.netbeans.lib.profiler.common.ProfilingSettings;
052: import org.netbeans.lib.profiler.global.CommonConstants;
053: import org.netbeans.lib.profiler.global.Platform;
054: import org.netbeans.lib.profiler.utils.MiscUtils;
055: import org.netbeans.modules.profiler.ProfilerIDESettings;
056: import org.netbeans.modules.profiler.ProfilerModule;
057: import org.netbeans.modules.profiler.ui.ProfilerDialogs;
058: import org.netbeans.modules.profiler.ui.stp.ProfilingSettingsManager;
059: import org.openide.DialogDescriptor;
060: import org.openide.ErrorManager;
061: import org.openide.NotifyDescriptor;
062: import org.openide.filesystems.FileLock;
063: import org.openide.filesystems.FileObject;
064: import org.openide.filesystems.FileUtil;
065: import org.openide.filesystems.Repository;
066: import org.openide.modules.InstalledFileLocator;
067: import org.openide.util.NbBundle;
068: import org.openide.util.RequestProcessor;
069: import org.openide.windows.TopComponent;
070: import org.openide.windows.WindowManager;
071: import java.awt.*;
072: import java.io.BufferedInputStream;
073: import java.io.BufferedOutputStream;
074: import java.io.File;
075: import java.io.IOException;
076: import java.io.InputStream;
077: import java.io.OutputStream;
078: import java.lang.reflect.InvocationTargetException;
079: import java.text.MessageFormat;
080: import java.util.*;
081: import javax.swing.*;
082: import javax.swing.border.EmptyBorder;
083: import javax.swing.event.ListSelectionEvent;
084: import javax.swing.event.ListSelectionListener;
085: import org.netbeans.modules.profiler.utilities.queries.SettingsFolderQuery;
086:
087: /**
088: * Utilities for interaction with the NetBeans IDE
089: *
090: * @author Tomas Hurka
091: * @author Ian Formanek
092: */
093: public final class IDEUtils {
094: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
095:
096: // -----
097: // I18N String constants
098: private static final String CREATE_NEW_CONFIGURATION_HINT = NbBundle
099: .getMessage(IDEUtils.class,
100: "IDEUtils_CreateNewConfigurationHint"); // NOI18N
101: private static final String SELECT_SETTINGS_CONFIGURATION_LABEL_TEXT = NbBundle
102: .getMessage(IDEUtils.class,
103: "IDEUtils_SelectSettingsConfigurationLabelText"); // NOI18N
104: private static final String SELECT_SETTINGS_CONFIGURATION_DIALOG_CAPTION = NbBundle
105: .getMessage(IDEUtils.class,
106: "IDEUtils_SelectSettingsConfigurationDialogCaption"); // NOI18N
107: private static final String INVALID_PLATFORM_PROJECT_MSG = NbBundle
108: .getMessage(IDEUtils.class,
109: "IDEUtils_InvalidPlatformProjectMsg"); // NOI18N
110: private static final String INVALID_PLATFORM_PROFILER_MSG = NbBundle
111: .getMessage(IDEUtils.class,
112: "IDEUtils_InvalidPlatformProfilerMsg"); // NOI18N
113: private static final String INVALID_TARGET_JVM_EXEFILE_ERROR = NbBundle
114: .getMessage(IDEUtils.class,
115: "IDEUtils_InvalidTargetJVMExeFileError"); // NOI18N // TODO: move to this package's bundle
116: private static final String ERROR_CONVERTING_PROFILING_SETTINGS_MESSAGE = NbBundle
117: .getMessage(IDEUtils.class,
118: "IDEUtils_ErrorConvertingProfilingSettingsMessage"); //NOI18N
119: private static final String LIST_ACCESS_NAME = NbBundle.getMessage(
120: IDEUtils.class, "IDEUtils_ListAccessName"); //NOI18N
121: private static final String OK_BUTTON_TEXT = NbBundle.getMessage(
122: IDEUtils.class, "IDEUtils_OkButtonText"); //NOI18N
123: // -----
124: public static final String SETTINGS_DIR = "org-netbeans-modules-profiler"; //NOI18N
125: private static final RequestProcessor profilerRequestProcessor = new RequestProcessor(
126: "Profiler Request Processor", 1); // NOI18N
127: private static final ErrorManager profilerErrorManager = ErrorManager
128: .getDefault().getInstance("org.netbeans.modules.profiler"); // NOI18N
129:
130: //~ Methods ------------------------------------------------------------------------------------------------------------------
131:
132: public static String getAntProfilerStartArgument15(int port,
133: int architecture) {
134: return getAntProfilerStartArgument(port, architecture,
135: CommonConstants.JDK_15_STRING);
136: }
137:
138: public static String getAntProfilerStartArgument16(int port,
139: int architecture) {
140: return getAntProfilerStartArgument(port, architecture,
141: CommonConstants.JDK_16_STRING);
142: }
143:
144: public static String getAntProfilerStartArgument17(int port,
145: int architecture) {
146: return getAntProfilerStartArgument(port, architecture,
147: CommonConstants.JDK_17_STRING);
148: }
149:
150: // Searches for a localized help. The default directory is <profiler_cluster>/docs/profiler,
151: // localized help is in <profiler_cluster>/docs/profiler_<locale_suffix> as obtained by NbBundle.getLocalizingSuffixes()
152: // see Issue 65429 (http://www.netbeans.org/issues/show_bug.cgi?id=65429)
153: public static String getHelpDir() {
154: Iterator suffixesIterator = NbBundle.getLocalizingSuffixes();
155: File localizedHelpDir = null;
156:
157: while (suffixesIterator.hasNext() && (localizedHelpDir == null)) {
158: localizedHelpDir = InstalledFileLocator.getDefault()
159: .locate("docs/profiler" + suffixesIterator.next(),
160: "org.netbeans.modules.profiler", false); //NOI18N
161: }
162:
163: if (localizedHelpDir == null) {
164: return null;
165: } else {
166: return localizedHelpDir.getPath();
167: }
168: }
169:
170: public static JavaPlatform getJavaPlatformByName(String platformName) {
171: if (platformName != null) {
172: JavaPlatform[] platforms = JavaPlatformManager.getDefault()
173: .getPlatforms(platformName, null);
174:
175: for (int i = 0; i < platforms.length; i++) {
176: JavaPlatform platform = platforms[i];
177:
178: if ((platformName != null)
179: && platform.getDisplayName().equals(
180: (platformName))) {
181: return platform;
182: }
183: }
184: }
185:
186: return null;
187: }
188:
189: public static String getLibsDir() {
190: final File dir = InstalledFileLocator.getDefault().locate(
191: ProfilerModule.LIBS_DIR + "/jfluid-server.jar",
192: "org.netbeans.lib.profiler", false); //NOI18N
193:
194: if (dir == null) {
195: return null;
196: } else {
197: return dir.getParentFile().getPath();
198: }
199: }
200:
201: public static Component getMainWindow() {
202: return WindowManager.getDefault().getMainWindow();
203: }
204:
205: public static int getPlatformArchitecture(JavaPlatform platform) {
206: assert platform != null : "Platform may not be NULL"; // NOI18N
207:
208: Map props = platform.getSystemProperties();
209: String arch = (String) props.get("sun.arch.data.model"); // NOI18N
210:
211: if (arch == null) {
212: return 32;
213: }
214:
215: return Integer.parseInt(arch);
216: }
217:
218: public static int getPlatformJDKMinor(JavaPlatform platform) {
219: assert platform != null : "Platform may not be NULL"; // NOI18N
220:
221: Map props = platform.getSystemProperties();
222: String ver = (String) props.get("java.version"); // NOI18N
223:
224: return Platform.getJDKMinorNumber(ver);
225: }
226:
227: /** Gets a version for to provided JavaPlatform. The platform passed cannot be null.
228: *
229: * @param platform A JavaPlatform for which we need the java executable path
230: * @return A path to java executable or null if not found
231: * @see CommonConstants.JDK_15_STRING
232: * @see CommonConstants.JDK_16_STRING
233: * @see CommonConstants.JDK_17_STRING
234: */
235: public static String getPlatformJDKVersion(JavaPlatform platform) {
236: assert platform != null : "Platform may not be NULL"; // NOI18N
237:
238: Map props = platform.getSystemProperties();
239: String ver = (String) props.get("java.version"); // NOI18N
240:
241: if (ver == null) {
242: return null;
243: }
244:
245: if (ver.startsWith("1.5")) {
246: return CommonConstants.JDK_15_STRING; // NOI18N
247: } else if (ver.startsWith("1.6")) {
248: return CommonConstants.JDK_16_STRING; // NOI18N
249: } else if (ver.startsWith("1.7")) {
250: return CommonConstants.JDK_17_STRING; // NOI18N
251: } else {
252: return null;
253: }
254: }
255:
256: /** Gets a path to java executable for specified platform. The platform passed cannot be null.
257: * Errors when obtaining the java executable will be reported to the user and null will be returned.
258: *
259: * @param platform A JavaPlatform for which we need the java executable path
260: * @return A path to java executable or null if not found
261: */
262: public static String getPlatformJavaFile(JavaPlatform platform) {
263: assert platform != null : "Platform may not be NULL"; // NOI18N
264:
265: FileObject fo = platform.findTool("java"); // NOI18N
266:
267: if (fo == null) { // probably invalid platform
268:
269: if (ProfilerIDESettings.getInstance()
270: .getJavaPlatformForProfiling() == null) {
271: // used platform defined for project
272: Profiler.getDefault().displayError(
273: MessageFormat.format(
274: INVALID_PLATFORM_PROJECT_MSG,
275: new Object[] { platform
276: .getDisplayName() }));
277: } else {
278: // used platform defined in Options / Profiler
279: Profiler.getDefault().displayError(
280: MessageFormat.format(
281: INVALID_PLATFORM_PROFILER_MSG,
282: new Object[] { platform
283: .getDisplayName() }));
284: }
285:
286: return null;
287: }
288:
289: String jvmExe = null;
290:
291: try {
292: File file = FileUtil.toFile(fo);
293: jvmExe = file.getAbsolutePath();
294: MiscUtils.checkFileForName(jvmExe);
295: } catch (Exception e) {
296: ErrorManager.getDefault().annotate(
297: e,
298: MessageFormat.format(
299: INVALID_TARGET_JVM_EXEFILE_ERROR,
300: new Object[] { jvmExe, e.getMessage() }));
301: ErrorManager.getDefault().notify(ErrorManager.ERROR, e);
302: }
303:
304: return jvmExe;
305: }
306:
307: public static RequestProcessor getProfilerRequestProcessor() {
308: return profilerRequestProcessor;
309: }
310:
311: public static Project getProjectFromSettingsFolder(
312: FileObject settingsFolder) {
313: if ((settingsFolder == null)
314: || !settingsFolder.getName().equals("profiler")) {
315: return null; // NOI18N
316: }
317:
318: FileObject privateFolder = settingsFolder.getParent();
319:
320: if ((privateFolder == null)
321: || !privateFolder.getName().equals("private")) {
322: return null; // NOI18N
323: }
324:
325: FileObject nbprojectFolder = privateFolder.getParent();
326:
327: if ((nbprojectFolder == null)
328: || !nbprojectFolder.getName().equals("nbproject")) {
329: return null; // NOI18N
330: }
331:
332: FileObject projectFolder = nbprojectFolder.getParent();
333:
334: if (projectFolder == null) {
335: return null;
336: }
337:
338: try {
339: return ProjectManager.getDefault().findProject(
340: projectFolder);
341: } catch (IOException e) {
342: return null;
343: }
344: }
345:
346: public static FileObject getProjectSettingsFolder(Project project,
347: boolean create) throws IOException {
348: if (project == null) { // global folder for attach
349:
350: return getSettingsFolder(true);
351: } else {
352: // resolve 'nbproject'
353: FileObject nbproject = project.getProjectDirectory()
354: .getFileObject("nbproject"); // NOI18N
355:
356: if ((nbproject == null) && create) {
357: nbproject = project.getProjectDirectory().createFolder(
358: "nbproject"); // NOI18N
359: }
360:
361: if (nbproject == null) {
362: return null;
363: }
364:
365: // resolve 'private'
366: FileObject privateFolder = nbproject
367: .getFileObject("private"); // NOI18N
368:
369: if ((privateFolder == null) && create) {
370: privateFolder = nbproject.createFolder("private"); // NOI18N
371: }
372:
373: if (privateFolder == null) {
374: return null;
375: }
376:
377: // resolve 'profiler'
378: FileObject prof = privateFolder.getFileObject("profiler"); // NOI18N
379:
380: if ((prof == null) && create) {
381: prof = privateFolder.createFolder("profiler"); // NOI18N
382: }
383:
384: return prof;
385: }
386: }
387:
388: public static String getServicesDir() {
389: // Need to search also for localized filters-default, there is a possibility that default en filters-default.xml won't be in Services directory.
390: final File dir = InstalledFileLocator.getDefault().locate(
391: "config/Services/filters-default.xml",
392: "org.netbeans.modules.profiler", true); //NOI18N
393:
394: if (dir == null) {
395: return null;
396: } else {
397: return dir.getParentFile().getPath();
398: }
399: }
400:
401: public static FileObject getSettingsFolder(final boolean create)
402: throws IOException {
403: return SettingsFolderQuery.getDefault().getSettingsFolder(
404: create);
405: // final FileObject folder = Repository.getDefault().getDefaultFileSystem().findResource("Services"); //NOI18N
406: // FileObject settingsFolder = folder.getFileObject(SettingsFolderQuery.getDefault().getSettingsFolder(), null);
407: //
408: // if ((settingsFolder == null) && create) {
409: // settingsFolder = folder.createFolder(SettingsFolderQuery.getDefault().getSettingsFolder());
410: // }
411: //
412: // return settingsFolder;
413: }
414:
415: /**
416: * @param temp the component
417: * @return the TopComponent that contains this component or null if not found (the componenet is not in any container or not under TopComponent).
418: */
419: public static TopComponent getTopComponent(Component temp) {
420: while (!(temp instanceof TopComponent)) {
421: temp = temp.getParent();
422:
423: if (temp == null) {
424: return null;
425: }
426: }
427:
428: return (TopComponent) temp;
429: }
430:
431: // Stores settings from .properties file to .xml properties file and then deletes the .properties file
432: public static void convertPropertiesToXML(FileObject propertiesFO,
433: FileObject xmlFO) {
434: Properties properties;
435: FileLock propertiesFOLock = null;
436: FileLock xmlFOLock = null;
437:
438: try {
439: // load the configuration from .properties file
440: propertiesFOLock = propertiesFO.lock();
441:
442: final InputStream fis = propertiesFO.getInputStream();
443: final BufferedInputStream bis = new BufferedInputStream(fis);
444: properties = new Properties();
445: properties.load(bis);
446: bis.close();
447: fis.close();
448:
449: // save the configuration to .xml file
450: xmlFOLock = xmlFO.lock();
451:
452: final OutputStream fos = xmlFO.getOutputStream(xmlFOLock);
453: final BufferedOutputStream bos = new BufferedOutputStream(
454: fos);
455: properties.storeToXML(bos, ""); //NOI18N
456: bos.close();
457: fos.close();
458:
459: // delete the .properties file
460: propertiesFO.delete(propertiesFOLock);
461: } catch (Exception e) {
462: ProfilerLogger.log(e);
463: ProfilerDialogs
464: .notify(new NotifyDescriptor.Message(
465: MessageFormat
466: .format(
467: ERROR_CONVERTING_PROFILING_SETTINGS_MESSAGE,
468: new Object[] {
469: FileUtil
470: .toFile(
471: propertiesFO)
472: .getPath(),
473: FileUtil.toFile(
474: xmlFO)
475: .getPath(),
476: e.getMessage() }),
477: NotifyDescriptor.WARNING_MESSAGE));
478: } finally {
479: if (propertiesFOLock != null) {
480: propertiesFOLock.releaseLock();
481: }
482:
483: if (xmlFOLock != null) {
484: xmlFOLock.releaseLock();
485: }
486: }
487: }
488:
489: public static Properties duplicateProperties(Properties props) {
490: Properties ret = new Properties();
491:
492: for (Enumeration e = props.keys(); e.hasMoreElements();) {
493: String key = (String) e.nextElement();
494: ret.setProperty(key, props.getProperty(key));
495: }
496:
497: return ret;
498: }
499:
500: public static ProgressHandle indeterminateProgress(String title,
501: final int timeout) {
502: final ProgressHandle ph = ProgressHandleFactory
503: .createHandle(title);
504: IDEUtils.runInEventDispatchThreadAndWait(new Runnable() {
505: public void run() {
506: ph.setInitialDelay(timeout);
507: ph.start();
508: }
509: });
510:
511: return ph;
512: }
513:
514: public static void runInEventDispatchThread(final Runnable r) {
515: if (SwingUtilities.isEventDispatchThread()) {
516: r.run();
517: } else {
518: SwingUtilities.invokeLater(r);
519: }
520: }
521:
522: public static void runInEventDispatchThreadAndWait(final Runnable r) {
523: if (SwingUtilities.isEventDispatchThread()) {
524: r.run();
525: } else {
526: try {
527: SwingUtilities.invokeAndWait(r);
528: } catch (InvocationTargetException e) {
529: profilerErrorManager.notify(e);
530: } catch (InterruptedException e) {
531: profilerErrorManager.notify(e);
532: }
533: }
534: }
535:
536: public static void runInProfilerRequestProcessor(final Runnable r) {
537: profilerRequestProcessor.post(r);
538: }
539:
540: /**
541: * Opens a dialog that allows the user to select one of existing profiling settings
542: */
543: public static ProfilingSettings selectSettings(Project project,
544: int type, ProfilingSettings[] availableSettings,
545: ProfilingSettings settingsToSelect) {
546: Object[] settings = new Object[availableSettings.length + 1];
547:
548: for (int i = 0; i < availableSettings.length; i++) {
549: settings[i] = availableSettings[i];
550: }
551:
552: settings[availableSettings.length] = CREATE_NEW_CONFIGURATION_HINT;
553:
554: // constuct the UI
555: final JLabel label = new JLabel(
556: SELECT_SETTINGS_CONFIGURATION_LABEL_TEXT);
557: final JButton okButton = new JButton(OK_BUTTON_TEXT);
558: final JPanel panel = new JPanel();
559: panel.setPreferredSize(new Dimension(450, 250));
560: panel.setBorder(new EmptyBorder(12, 12, 12, 12));
561: panel.setLayout(new BorderLayout(0, 5));
562: panel.add(label, BorderLayout.NORTH);
563:
564: final JList list = new JList(settings);
565: label.setLabelFor(list);
566: list.getAccessibleContext().setAccessibleName(LIST_ACCESS_NAME);
567: list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
568: list.addListSelectionListener(new ListSelectionListener() {
569: public void valueChanged(ListSelectionEvent e) {
570: okButton.setEnabled(list.getSelectedIndex() != -1);
571: }
572: });
573:
574: if (settingsToSelect != null) {
575: list.setSelectedValue(settingsToSelect, true);
576: } else {
577: list.setSelectedIndex(0);
578: }
579:
580: panel.add(new JScrollPane(list), BorderLayout.CENTER);
581:
582: final DialogDescriptor dd = new DialogDescriptor(
583: panel,
584: SELECT_SETTINGS_CONFIGURATION_DIALOG_CAPTION,
585: true,
586: new Object[] { okButton, DialogDescriptor.CANCEL_OPTION },
587: okButton, 0, null, null);
588: final Dialog d = ProfilerDialogs.createDialog(dd);
589: d.setVisible(true);
590:
591: if (dd.getValue() == okButton) {
592: final int selectedIndex = list.getSelectedIndex();
593:
594: if (selectedIndex != -1) { // TODO [ian]: do not allow this, disable OK button if there is no selection
595:
596: if (selectedIndex < (settings.length - 1)) {
597: ProfilingSettings selectedSettings = (ProfilingSettings) settings[selectedIndex];
598: selectedSettings.setProfilingType(type);
599:
600: return selectedSettings;
601: } else { // create a new setting
602:
603: ProfilingSettings newSettings = ProfilingSettingsManager
604: .getDefault().createNewSettings(type,
605: availableSettings);
606:
607: if (newSettings == null) {
608: return null; // cancelled by the user
609: }
610:
611: newSettings.setProfilingType(type);
612:
613: return newSettings;
614: }
615: }
616: }
617:
618: return null;
619: }
620:
621: private static String getAntProfilerStartArgument(int port,
622: int architecture, String jdkVersion) {
623: String ld = IDEUtils.getLibsDir();
624:
625: // -agentpath:D:/Testing/41 userdir/lib/deployed/jdk15/windows/profilerinterface.dll=D:\Testing\41 userdir\lib,5140
626: return "-agentpath:" // NOI18N
627: + Platform.getAgentNativeLibFullName(ld, false,
628: jdkVersion, architecture)
629: + "=" // NOI18N
630: + ld
631: + "," // NOI18N
632: + port
633: + "," // NOI18N
634: + System.getProperty("profiler.agent.connect.timeout",
635: "10"); // NOI18N // 10 seconds timeout by default
636: }
637:
638: private static ArrayList getSettings(final Project project,
639: final int mask) {
640: final ArrayList matching = new ArrayList();
641: ProfilingSettings[] projectSettings = ProfilingSettingsManager
642: .getDefault().getProfilingSettings(project)
643: .getProfilingSettings();
644:
645: for (ProfilingSettings settings : projectSettings) {
646: if (matchesMask(settings, mask)) {
647: matching.add(settings);
648: }
649: }
650:
651: return matching;
652: }
653:
654: private static String forwardSlashes(String text) {
655: return text.replaceAll("\\\\", "/"); // NOI18N
656: }
657:
658: private static boolean matchesMask(
659: final ProfilingSettings settings, final int mask) {
660: // TODO: should only check Monitor/CPU/Memory
661: return org.netbeans.modules.profiler.ui.stp.Utils
662: .isCPUSettings(settings);
663:
664: // return (settings.getProfilingType() & mask) != 0;
665: }
666: }
|