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.ant.freeform;
043:
044: import java.awt.event.ActionEvent;
045: import java.io.File;
046: import java.io.IOException;
047: import java.text.MessageFormat;
048: import java.util.ArrayList;
049: import java.util.Arrays;
050: import java.util.Collection;
051: import java.util.Collections;
052: import java.util.HashMap;
053: import java.util.HashSet;
054: import java.util.Iterator;
055: import java.util.LinkedHashSet;
056: import java.util.List;
057: import java.util.Map;
058: import java.util.Properties;
059: import java.util.Set;
060: import java.util.logging.Level;
061: import java.util.logging.Logger;
062: import java.util.regex.Pattern;
063: import java.util.regex.PatternSyntaxException;
064: import javax.swing.AbstractAction;
065: import javax.swing.Action;
066: import javax.swing.JSeparator;
067: import org.apache.tools.ant.module.api.support.ActionUtils;
068: import org.netbeans.modules.ant.freeform.spi.support.Util;
069: import org.netbeans.modules.ant.freeform.ui.ProjectNodeWrapper;
070: import org.netbeans.modules.ant.freeform.ui.UnboundTargetAlert;
071: import org.netbeans.spi.project.ActionProvider;
072: import org.netbeans.spi.project.support.ant.AntProjectHelper;
073: import org.netbeans.spi.project.ui.support.CommonProjectActions;
074: import org.netbeans.spi.project.ui.support.DefaultProjectOperations;
075: import org.netbeans.spi.project.ui.support.ProjectSensitiveActions;
076: import org.openide.DialogDisplayer;
077: import org.openide.ErrorManager;
078: import org.openide.NotifyDescriptor;
079: import org.openide.actions.FindAction;
080: import org.openide.filesystems.FileObject;
081: import org.openide.filesystems.FileUtil;
082: import org.openide.loaders.DataObject;
083: import org.openide.util.Lookup;
084: import org.openide.util.NbBundle;
085: import org.openide.util.actions.SystemAction;
086: import org.openide.util.lookup.Lookups;
087: import org.w3c.dom.Element;
088:
089: /**
090: * Action bindings for a freeform project.
091: * @author Jesse Glick
092: */
093: public final class Actions implements ActionProvider {
094:
095: private static final Logger LOG = Logger.getLogger(Actions.class
096: .getName());
097:
098: /**
099: * Some routine global actions for which we can supply a display name.
100: * These are IDE-specific.
101: */
102: private static final Set<String> COMMON_IDE_GLOBAL_ACTIONS = new HashSet<String>(
103: Arrays.asList(ActionProvider.COMMAND_DEBUG,
104: ActionProvider.COMMAND_DELETE,
105: ActionProvider.COMMAND_COPY,
106: ActionProvider.COMMAND_MOVE,
107: ActionProvider.COMMAND_RENAME));
108: /**
109: * Similar to {@link #COMMON_IDE_GLOBAL_ACTIONS}, but these are not IDE-specific.
110: * We also mark all of these as bound in the project; if the user
111: * does not really have a binding, they are prompted for one when
112: * the action is "run".
113: */
114: private static final Set<String> COMMON_NON_IDE_GLOBAL_ACTIONS = new HashSet<String>(
115: Arrays.asList(ActionProvider.COMMAND_BUILD,
116: ActionProvider.COMMAND_CLEAN,
117: ActionProvider.COMMAND_REBUILD,
118: ActionProvider.COMMAND_RUN,
119: ActionProvider.COMMAND_TEST,
120: // XXX JavaProjectConstants.COMMAND_JAVADOC
121: "javadoc", // NOI18N
122: // XXX WebProjectConstants.COMMAND_REDEPLOY
123: // XXX should this really be here? perhaps not, once web part of #46886 is implemented...
124: "redeploy",
125: // XXX deploy action of EJB freeform project
126: "deploy")); // NOI18N
127:
128: private final FreeformProject project;
129:
130: /**
131: * Create a new action provider.
132: * @param project the associated project
133: */
134: public Actions(FreeformProject project) {
135: this .project = project;
136: }
137:
138: public String[] getSupportedActions() {
139: Element genldata = project.getPrimaryConfigurationData();
140: Element actionsEl = Util.findElement(genldata, "ide-actions",
141: FreeformProjectType.NS_GENERAL); // NOI18N
142: if (actionsEl == null) {
143: return new String[0];
144: }
145: // Use a set, not a list, since when using context you can define one action several times:
146: Set<String> names = new LinkedHashSet<String>();
147: for (Element actionEl : Util.findSubElements(actionsEl)) {
148: names.add(actionEl.getAttribute("name")); // NOI18N
149: }
150: // #46886: also always enable all common global actions, in case they should be selected:
151: names.addAll(COMMON_NON_IDE_GLOBAL_ACTIONS);
152: names.add(COMMAND_RENAME);
153: names.add(COMMAND_MOVE);
154: names.add(COMMAND_COPY);
155: names.add(COMMAND_DELETE);
156: return names.toArray(new String[names.size()]);
157: }
158:
159: public boolean isActionEnabled(String command, Lookup context)
160: throws IllegalArgumentException {
161: if (COMMAND_DELETE.equals(command)) {
162: return true;
163: }
164: if (COMMAND_COPY.equals(command)) {
165: return true;
166: }
167: if (COMMAND_RENAME.equals(command)) {
168: return true;
169: }
170: if (COMMAND_MOVE.equals(command)) {
171: return true;
172: }
173:
174: Element genldata = project.getPrimaryConfigurationData();
175: Element actionsEl = Util.findElement(genldata, "ide-actions",
176: FreeformProjectType.NS_GENERAL); // NOI18N
177: if (actionsEl == null) {
178: throw new IllegalArgumentException("No commands supported"); // NOI18N
179: }
180: boolean foundAction = false;
181: for (Element actionEl : Util.findSubElements(actionsEl)) {
182: if (actionEl.getAttribute("name").equals(command)) { // NOI18N
183: foundAction = true;
184: // XXX perhaps check also existence of script
185: Element contextEl = Util.findElement(actionEl,
186: "context", FreeformProjectType.NS_GENERAL); // NOI18N
187: if (contextEl != null) {
188: // Check whether the context contains files all in this folder,
189: // matching the pattern if any, and matching the arity (single/multiple).
190: Map<String, FileObject> selection = findSelection(
191: contextEl, context, project);
192: LOG
193: .log(
194: Level.FINE,
195: "detected selection {0} for command {1} in {2}",
196: new Object[] { selection, command,
197: project });
198: if (selection.size() == 1) {
199: // Definitely enabled.
200: return true;
201: } else if (!selection.isEmpty()) {
202: // Multiple selection; check arity.
203: Element arityEl = Util
204: .findElement(contextEl, "arity",
205: FreeformProjectType.NS_GENERAL); // NOI18N
206: assert arityEl != null : "No <arity> in <context> for "
207: + command;
208: if (Util.findElement(arityEl,
209: "separated-files",
210: FreeformProjectType.NS_GENERAL) != null) { // NOI18N
211: // Supports multiple selection, take it.
212: return true;
213: }
214: }
215: } else {
216: // Not context-sensitive.
217: return true;
218: }
219: }
220: }
221: if (COMMON_NON_IDE_GLOBAL_ACTIONS.contains(command)) {
222: // #46886: these are always enabled if they are not specifically bound.
223: return true;
224: }
225: if (foundAction) {
226: // Was at least one context-aware variant but did not match.
227: return false;
228: } else {
229: throw new IllegalArgumentException("Unrecognized command: "
230: + command); // NOI18N
231: }
232: }
233:
234: public void invokeAction(String command, Lookup context)
235: throws IllegalArgumentException {
236: if (COMMAND_DELETE.equals(command)) {
237: DefaultProjectOperations
238: .performDefaultDeleteOperation(project);
239: return;
240: }
241: if (COMMAND_COPY.equals(command)) {
242: DefaultProjectOperations
243: .performDefaultCopyOperation(project);
244: return;
245: }
246: if (COMMAND_RENAME.equals(command)) {
247: DefaultProjectOperations.performDefaultRenameOperation(
248: project, null);
249: return;
250: }
251: if (COMMAND_MOVE.equals(command)) {
252: DefaultProjectOperations
253: .performDefaultMoveOperation(project);
254: return;
255: }
256:
257: Element genldata = project.getPrimaryConfigurationData();
258: Element actionsEl = Util.findElement(genldata, "ide-actions",
259: FreeformProjectType.NS_GENERAL); // NOI18N
260: if (actionsEl == null) {
261: throw new IllegalArgumentException("No commands supported"); // NOI18N
262: }
263: boolean foundAction = false;
264: for (Element actionEl : Util.findSubElements(actionsEl)) {
265: if (actionEl.getAttribute("name").equals(command)) { // NOI18N
266: foundAction = true;
267: runConfiguredAction(project, actionEl, context);
268: }
269: }
270: if (!foundAction) {
271: if (COMMON_NON_IDE_GLOBAL_ACTIONS.contains(command)) {
272: // #46886: try to bind it.
273: if (addGlobalBinding(command)) {
274: // If bound, run it immediately.
275: invokeAction(command, context);
276: }
277: } else {
278: throw new IllegalArgumentException(
279: "Unrecognized command: " + command); // NOI18N
280: }
281: }
282: }
283:
284: /**
285: * Find a file selection in a lookup context based on a project.xml <context> declaration.
286: * If all DataObject's (or FileObject's) in the lookup match the folder named in the declaration,
287: * and match any optional pattern declaration, then they are returned as a map from relative
288: * path to actual file object. Otherwise an empty map is returned.
289: */
290: private static Map<String, FileObject> findSelection(
291: Element contextEl, Lookup context, FreeformProject project) {
292: Collection<? extends DataObject> filesDO = context
293: .lookupAll(DataObject.class);
294: if (filesDO.isEmpty()) {
295: return Collections.emptyMap();
296: }
297: Collection<FileObject> _files = new ArrayList<FileObject>(
298: filesDO.size());
299: for (DataObject d : filesDO) {
300: _files.add(d.getPrimaryFile());
301: }
302: Collection<? extends FileObject> files = _files;
303: Element folderEl = Util.findElement(contextEl, "folder",
304: FreeformProjectType.NS_GENERAL); // NOI18N
305: assert folderEl != null : "Must have <folder> in <context>";
306: String rawtext = Util.findText(folderEl);
307: assert rawtext != null : "Must have text contents in <folder>";
308: String evaltext = project.evaluator().evaluate(rawtext);
309: if (evaltext == null) {
310: return Collections.emptyMap();
311: }
312: FileObject folder = project.helper()
313: .resolveFileObject(evaltext);
314: if (folder == null) {
315: return Collections.emptyMap();
316: }
317: Pattern pattern = null;
318: Element patternEl = Util.findElement(contextEl, "pattern",
319: FreeformProjectType.NS_GENERAL); // NOI18N
320: if (patternEl != null) {
321: String text = Util.findText(patternEl);
322: assert text != null : "Must have text contents in <pattern>";
323: try {
324: pattern = Pattern.compile(text);
325: } catch (PatternSyntaxException e) {
326: org.netbeans.modules.ant.freeform.Util.err
327: .annotate(
328: e,
329: ErrorManager.UNKNOWN,
330: "From <pattern> in "
331: + FileUtil
332: .getFileDisplayName(project
333: .getProjectDirectory()
334: .getFileObject(
335: AntProjectHelper.PROJECT_XML_PATH)),
336: null, null, null); // NOI18N
337: org.netbeans.modules.ant.freeform.Util.err.notify(e);
338: return Collections.emptyMap();
339: }
340: }
341: Map<String, FileObject> result = new HashMap<String, FileObject>();
342: for (FileObject file : files) {
343: String path = FileUtil.getRelativePath(folder, file);
344: if (path == null) {
345: return Collections.emptyMap();
346: }
347: if (pattern != null && !pattern.matcher(path).find()) {
348: return Collections.emptyMap();
349: }
350: result.put(path, file);
351: }
352: return result;
353: }
354:
355: /**
356: * Run a project action as described by subelements <script> and <target>.
357: */
358: private static void runConfiguredAction(FreeformProject project,
359: Element actionEl, Lookup context) {
360: String script;
361: Element scriptEl = Util.findElement(actionEl, "script",
362: FreeformProjectType.NS_GENERAL); // NOI18N
363: if (scriptEl != null) {
364: script = Util.findText(scriptEl);
365: } else {
366: script = "build.xml"; // NOI18N
367: }
368: String scriptLocation = project.evaluator().evaluate(script);
369: FileObject scriptFile = null;
370: if (scriptLocation != null) {
371: scriptFile = project.helper().resolveFileObject(
372: scriptLocation);
373: }
374: if (scriptFile == null) {
375: //#57011: if the script does not exist, show a warning:
376: NotifyDescriptor nd = new NotifyDescriptor.Message(
377: MessageFormat.format(NbBundle.getMessage(
378: Actions.class,
379: "LBL_ScriptFileNotFoundError"),
380: new Object[] { scriptLocation }),
381: NotifyDescriptor.ERROR_MESSAGE);
382:
383: DialogDisplayer.getDefault().notify(nd);
384: return;
385: }
386: List<Element> targets = Util.findSubElements(actionEl);
387: List<String> targetNames = new ArrayList<String>(targets.size());
388: for (Element targetEl : targets) {
389: if (!targetEl.getLocalName().equals("target")) { // NOI18N
390: continue;
391: }
392: targetNames.add(Util.findText(targetEl));
393: }
394: String[] targetNameArray;
395: if (!targetNames.isEmpty()) {
396: targetNameArray = targetNames
397: .toArray(new String[targetNames.size()]);
398: } else {
399: // Run default target.
400: targetNameArray = null;
401: }
402: Properties props = new Properties();
403: Element contextEl = Util.findElement(actionEl, "context",
404: FreeformProjectType.NS_GENERAL); // NOI18N
405: if (contextEl != null) {
406: Map<String, FileObject> selection = findSelection(
407: contextEl, context, project);
408: if (selection.isEmpty()) {
409: return;
410: }
411: String separator = null;
412: if (selection.size() > 1) {
413: // Find the right separator.
414: Element arityEl = Util.findElement(contextEl, "arity",
415: FreeformProjectType.NS_GENERAL); // NOI18N
416: assert arityEl != null : "No <arity> in <context> for "
417: + actionEl.getAttribute("name");
418: Element sepFilesEl = Util.findElement(arityEl,
419: "separated-files",
420: FreeformProjectType.NS_GENERAL); // NOI18N
421: if (sepFilesEl == null) {
422: // Only handles single files -> skip it.
423: return;
424: }
425: separator = Util.findText(sepFilesEl);
426: }
427: Element formatEl = Util.findElement(contextEl, "format",
428: FreeformProjectType.NS_GENERAL); // NOI18N
429: assert formatEl != null : "No <format> in <context> for "
430: + actionEl.getAttribute("name");
431: String format = Util.findText(formatEl);
432: StringBuffer buf = new StringBuffer();
433: Iterator<Map.Entry<String, FileObject>> it = selection
434: .entrySet().iterator();
435: while (it.hasNext()) {
436: Map.Entry<String, FileObject> entry = it.next();
437: if (format.equals("absolute-path")) { // NOI18N
438: File f = FileUtil.toFile(entry.getValue());
439: if (f == null) {
440: // Not a disk file??
441: return;
442: }
443: buf.append(f.getAbsolutePath());
444: } else if (format.equals("relative-path")) { // NOI18N
445: buf.append(entry.getKey());
446: } else if (format.equals("absolute-path-noext")) { // NOI18N
447: File f = FileUtil.toFile(entry.getValue());
448: if (f == null) {
449: // Not a disk file??
450: return;
451: }
452: String path = f.getAbsolutePath();
453: int dot = path.lastIndexOf('.');
454: if (dot > path.lastIndexOf('/')) {
455: path = path.substring(0, dot);
456: }
457: buf.append(path);
458: } else if (format.equals("relative-path-noext")) { // NOI18N
459: String path = entry.getKey();
460: int dot = path.lastIndexOf('.');
461: if (dot > path.lastIndexOf('/')) {
462: path = path.substring(0, dot);
463: }
464: buf.append(path);
465: } else {
466: assert format.equals("java-name") : format;
467: String path = entry.getKey();
468: int dot = path.lastIndexOf('.');
469: String dotless;
470: if (dot == -1 || dot < path.lastIndexOf('/')) {
471: dotless = path;
472: } else {
473: dotless = path.substring(0, dot);
474: }
475: String javaname = dotless.replace('/', '.');
476: buf.append(javaname);
477: }
478: if (it.hasNext()) {
479: assert separator != null;
480: buf.append(separator);
481: }
482: }
483: Element propEl = Util.findElement(contextEl, "property",
484: FreeformProjectType.NS_GENERAL); // NOI18N
485: assert propEl != null : "No <property> in <context> for "
486: + actionEl.getAttribute("name");
487: String prop = Util.findText(propEl);
488: assert prop != null : "Must have text contents in <property>";
489: props.setProperty(prop, buf.toString());
490: }
491: for (Element propEl : targets) {
492: if (!propEl.getLocalName().equals("property")) { // NOI18N
493: continue;
494: }
495: String rawtext = Util.findText(propEl);
496: if (rawtext == null) {
497: // Legal to have e.g. <property name="intentionally-left-blank"/>
498: rawtext = ""; // NOI18N
499: }
500: String evaltext = project.evaluator().evaluate(rawtext); // might be null
501: if (evaltext != null) {
502: props
503: .setProperty(propEl.getAttribute("name"),
504: evaltext); // NOI18N
505: }
506: }
507: TARGET_RUNNER.runTarget(scriptFile, targetNameArray, props);
508: }
509:
510: /**
511: * Build the context menu for a project.
512: * @param p a freeform project
513: * @return a list of actions (or null for separators)
514: */
515: public static Action[] createContextMenu(FreeformProject p) {
516: List<Action> actions = new ArrayList<Action>();
517: actions.add(CommonProjectActions.newFileAction());
518: // Requested actions.
519: Element genldata = p.getPrimaryConfigurationData();
520: Element viewEl = Util.findElement(genldata, "view",
521: FreeformProjectType.NS_GENERAL); // NOI18N
522: if (viewEl != null) {
523: Element contextMenuEl = Util.findElement(viewEl,
524: "context-menu", FreeformProjectType.NS_GENERAL); // NOI18N
525: if (contextMenuEl != null) {
526: actions.add(null);
527: for (Element actionEl : Util
528: .findSubElements(contextMenuEl)) {
529: if (actionEl.getLocalName().equals("ide-action")) { // NOI18N
530: String cmd = actionEl.getAttribute("name");
531: String displayName;
532: if (COMMON_IDE_GLOBAL_ACTIONS.contains(cmd)
533: || COMMON_NON_IDE_GLOBAL_ACTIONS
534: .contains(cmd)) {
535: displayName = NbBundle.getMessage(
536: Actions.class, "CMD_" + cmd);
537: } else {
538: // OK, fall back to raw name.
539: displayName = cmd;
540: }
541: actions.add(ProjectSensitiveActions
542: .projectCommandAction(cmd, displayName,
543: null));
544: } else if (actionEl.getLocalName().equals(
545: "separator")) { // NOI18N
546: actions.add(null);
547: } else {
548: assert actionEl.getLocalName().equals("action") : actionEl;
549: actions.add(new CustomAction(p, actionEl));
550: }
551: }
552: }
553: }
554: addFromLayers(actions, "Projects/Profiler_Actions_temporary"); //NOI18N
555: // Back to generic actions.
556: actions.add(null);
557: actions.add(CommonProjectActions.setAsMainProjectAction());
558: actions.add(CommonProjectActions.openSubprojectsAction());
559: actions.add(CommonProjectActions.closeProjectAction());
560: actions.add(null);
561: actions.add(CommonProjectActions.renameProjectAction());
562: actions.add(CommonProjectActions.moveProjectAction());
563: actions.add(CommonProjectActions.copyProjectAction());
564: actions.add(CommonProjectActions.deleteProjectAction());
565: actions.add(null);
566: actions.add(SystemAction.get(FindAction.class));
567:
568: // honor #57874 contract, see #58624:
569: actions.add(ProjectNodeWrapper.GENERIC_PROJECTS_ACTIONS_MARKER);
570:
571: actions.add(null);
572: actions.add(CommonProjectActions.customizeProjectAction());
573: return actions.toArray(new Action[actions.size()]);
574: }
575:
576: private static void addFromLayers(List<Action> actions, String path) {
577: Lookup look = Lookups.forPath(path);
578: for (Object next : look.lookupAll(Object.class)) {
579: if (next instanceof Action) {
580: actions.add((Action) next);
581: } else if (next instanceof JSeparator) {
582: actions.add(null);
583: }
584: }
585: }
586:
587: private static final class CustomAction extends AbstractAction {
588:
589: private final FreeformProject p;
590: private final Element actionEl;
591:
592: public CustomAction(FreeformProject p, Element actionEl) {
593: this .p = p;
594: this .actionEl = actionEl;
595: }
596:
597: public void actionPerformed(ActionEvent e) {
598: runConfiguredAction(p, actionEl, Lookup.EMPTY);
599: }
600:
601: public boolean isEnabled() {
602: String script;
603: Element scriptEl = Util.findElement(actionEl, "script",
604: FreeformProjectType.NS_GENERAL); // NOI18N
605: if (scriptEl != null) {
606: script = Util.findText(scriptEl);
607: } else {
608: script = "build.xml"; // NOI18N
609: }
610: String scriptLocation = p.evaluator().evaluate(script);
611: return p.helper().resolveFileObject(scriptLocation) != null;
612: }
613:
614: public Object getValue(String key) {
615: if (key.equals(Action.NAME)) {
616: Element labelEl = Util.findElement(actionEl, "label",
617: FreeformProjectType.NS_GENERAL); // NOI18N
618: return Util.findText(labelEl);
619: } else {
620: return super .getValue(key);
621: }
622: }
623:
624: }
625:
626: // Overridable for unit tests only:
627: static TargetRunner TARGET_RUNNER = new TargetRunner();
628:
629: static class TargetRunner {
630: public TargetRunner() {
631: }
632:
633: public void runTarget(FileObject scriptFile,
634: String[] targetNameArray, Properties props) {
635: try {
636: ActionUtils.runTarget(scriptFile, targetNameArray,
637: props);
638: } catch (IOException e) {
639: ErrorManager.getDefault().notify(e);
640: }
641: }
642: }
643:
644: /**
645: * Prompt the user to make a binding for a common global command.
646: * Available targets are shown. If one is selected, it is bound
647: * (and also added to the context menu of the project), as if the user
648: * had picked it in {@link TargetMappingPanel}.
649: * @param command the command name as in {@link ActionProvider}
650: * @return true if a binding was successfully created, false if it was cancelled
651: * @see "#46886"
652: */
653: private boolean addGlobalBinding(String command) {
654: try {
655: return new UnboundTargetAlert(project, command).accepted();
656: } catch (IOException e) {
657: // Problem generating bindings - so skip it.
658: ErrorManager.getDefault().notify(e);
659: return false;
660: }
661: }
662:
663: }
|