~ubuntu-branches/ubuntu/quantal/netbeans/quantal

« back to all changes in this revision

Viewing changes to j2ee/ejbfreeform/src/org/netbeans/modules/j2ee/ejbfreeform/EjbFreeFormActionProvider.java

  • Committer: Bazaar Package Importer
  • Author(s): Marek Slama
  • Date: 2008-01-29 14:11:22 UTC
  • Revision ID: james.westby@ubuntu.com-20080129141122-fnzjbo11ntghxfu7
Tags: upstream-6.0.1
ImportĀ upstreamĀ versionĀ 6.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
3
 *
 
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 
5
 *
 
6
 * The contents of this file are subject to the terms of either the GNU
 
7
 * General Public License Version 2 only ("GPL") or the Common
 
8
 * Development and Distribution License("CDDL") (collectively, the
 
9
 * "License"). You may not use this file except in compliance with the
 
10
 * License. You can obtain a copy of the License at
 
11
 * http://www.netbeans.org/cddl-gplv2.html
 
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 
13
 * specific language governing permissions and limitations under the
 
14
 * License.  When distributing the software, include this License Header
 
15
 * Notice in each file and include the License file at
 
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 
17
 * particular file as subject to the "Classpath" exception as provided
 
18
 * by Sun in the GPL Version 2 section of the License file that
 
19
 * accompanied this code. If applicable, add the following below the
 
20
 * License Header, with the fields enclosed by brackets [] replaced by
 
21
 * your own identifying information:
 
22
 * "Portions Copyrighted [year] [name of copyright owner]"
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
26
 * The Original Software is NetBeans. The Initial Developer of the Original
 
27
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 
28
 * Microsystems, Inc. All Rights Reserved.
 
29
 *
 
30
 * If you wish your version of this file to be governed by only the CDDL
 
31
 * or only the GPL Version 2, indicate your decision by adding
 
32
 * "[Contributor] elects to include this software in this distribution
 
33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 
34
 * single choice of license, a recipient has the option to distribute
 
35
 * your version of this file under either the CDDL, the GPL Version 2 or
 
36
 * to extend the choice of license to its licensees as provided above.
 
37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 
38
 * Version 2 license, then the option applies only if the new code is
 
39
 * made subject to such option by the copyright holder.
 
40
 */
 
41
 
 
42
package org.netbeans.modules.j2ee.ejbfreeform;
 
43
 
 
44
import java.io.BufferedOutputStream;
 
45
import java.io.IOException;
 
46
import java.io.InputStream;
 
47
import java.io.OutputStream;
 
48
import java.util.Iterator;
 
49
import java.util.logging.Level;
 
50
import java.util.logging.Logger;
 
51
import javax.swing.JButton;
 
52
import javax.xml.parsers.ParserConfigurationException;
 
53
import javax.xml.parsers.SAXParser;
 
54
import javax.xml.parsers.SAXParserFactory;
 
55
import org.netbeans.api.java.project.JavaProjectConstants;
 
56
import org.netbeans.api.project.Project;
 
57
import org.netbeans.api.project.ProjectInformation;
 
58
import org.netbeans.api.project.ProjectManager;
 
59
import org.netbeans.api.project.ProjectUtils;
 
60
import org.netbeans.modules.ant.freeform.spi.support.Util;
 
61
import org.netbeans.spi.project.ActionProvider;
 
62
import org.netbeans.spi.project.AuxiliaryConfiguration;
 
63
import org.netbeans.spi.project.support.ant.AntProjectHelper;
 
64
import org.netbeans.spi.project.support.ant.EditableProperties;
 
65
import org.openide.DialogDisplayer;
 
66
import org.openide.NotifyDescriptor;
 
67
import org.openide.cookies.EditCookie;
 
68
import org.openide.cookies.LineCookie;
 
69
import org.openide.filesystems.FileLock;
 
70
import org.openide.filesystems.FileObject;
 
71
import org.openide.filesystems.FileUtil;
 
72
import org.openide.loaders.DataObject;
 
73
import org.openide.loaders.DataObjectNotFoundException;
 
74
import org.openide.text.Line;
 
75
import org.openide.util.Exceptions;
 
76
import org.openide.util.NbBundle;
 
77
import org.openide.xml.XMLUtil;
 
78
import org.w3c.dom.Comment;
 
79
import org.w3c.dom.Document;
 
80
import org.w3c.dom.Element;
 
81
import org.xml.sax.Attributes;
 
82
import org.xml.sax.InputSource;
 
83
import org.xml.sax.Locator;
 
84
import org.xml.sax.SAXException;
 
85
import org.xml.sax.helpers.DefaultHandler;
 
86
 
 
87
/**
 
88
 * Handles providing implementations of some Web-oriented IDE-specific actions.
 
89
 *
 
90
 * @author Libor Kotouc
 
91
 * @author Andrei Badea
 
92
 */
 
93
public class EjbFreeFormActionProvider implements ActionProvider {
 
94
    
 
95
    /**
 
96
     * Script to hold file-sensitive generated targets like compile.single.
 
97
     * (Or for generated targets for debug which cannot reuse any existing target body.)
 
98
     * These pick up at least project.dir from project.xml and the entire
 
99
     * target body is fixed by the IDE, except for some strings determined
 
100
     * by information from project.xml like the classpath. The basedir
 
101
     * is set to the project directory so that properties match their
 
102
     * semantics in project.xml.
 
103
     */
 
104
    static final String FILE_SCRIPT_PATH = "nbproject/ide-file-targets.xml"; // NOI18N
 
105
    
 
106
    /**
 
107
     * Script to hold non-file-sensitive generated targets like debug.
 
108
     * These import the original build script and share its basedir, so that
 
109
     * properties match the semantics of build.xml.
 
110
     */
 
111
    static final String GENERAL_SCRIPT_PATH = "nbproject/ide-targets.xml"; // NOI18N
 
112
    
 
113
    private static final String LOAD_PROPS_TARGET = "-load-props"; // NOI18N
 
114
    private static final String CHECK_PROPS_TARGET = "-check-props"; // NOI18N
 
115
    private static final String INIT_TARGET = "-init"; // NOI18N
 
116
    private static final String DEBUG_TARGET = "debug-nb"; // NOI18N
 
117
    private static final String DISPLAY_BROWSER = "debug-display-browser"; // NOI18N
 
118
 
 
119
    private static final String[] DEBUG_PROPERTIES = new String[] {
 
120
        EjbFreeformProperties.JPDA_SESSION_NAME,
 
121
        EjbFreeformProperties.JPDA_HOST,
 
122
        EjbFreeformProperties.JPDA_ADDRESS,
 
123
        EjbFreeformProperties.JPDA_TRANSPORT,
 
124
        EjbFreeformProperties.DEBUG_SOURCEPATH,
 
125
    };
 
126
            
 
127
    private static final String DEBUG_PROPERTIES_TEMPLATE = "/org/netbeans/modules/j2ee/ejbfreeform/resources/debug-properties.template"; // NOI18N
 
128
               
 
129
    private final Project project;
 
130
    private final AntProjectHelper helper;
 
131
    private final AuxiliaryConfiguration aux;
 
132
    
 
133
    private static final String[] SUPPORTED_ACTIONS = {
 
134
        ActionProvider.COMMAND_DEBUG,
 
135
    };
 
136
    
 
137
    /**
 
138
     * Creates a new instance of EjbFreeFormActionProvider 
 
139
     */
 
140
    public EjbFreeFormActionProvider(Project aProject, AntProjectHelper aHelper, AuxiliaryConfiguration aAux) {
 
141
        project = aProject;
 
142
        helper = aHelper;
 
143
        aux = aAux;
 
144
    }
 
145
 
 
146
    public boolean isActionEnabled(String command, org.openide.util.Lookup context) throws IllegalArgumentException {
 
147
        boolean enabled = false;
 
148
        if (command.equals(ActionProvider.COMMAND_DEBUG))
 
149
            enabled = true;
 
150
        return enabled;
 
151
    }
 
152
 
 
153
    public void invokeAction(String command, org.openide.util.Lookup context) throws IllegalArgumentException {
 
154
        try {
 
155
            try {
 
156
                if (command.equals(ActionProvider.COMMAND_DEBUG))
 
157
                    handleDebug();
 
158
                } catch (SAXException e) {
 
159
                    throw (IOException) new IOException(e.toString()).initCause(e);
 
160
                }
 
161
        } catch (IOException e) {
 
162
            Exceptions.printStackTrace(e);
 
163
        }
 
164
    }
 
165
 
 
166
    public String[] getSupportedActions() {
 
167
        return SUPPORTED_ACTIONS;
 
168
    }
 
169
    
 
170
    private void handleDebug() throws IOException, SAXException {
 
171
        //allow user to confirm target generation
 
172
        if (!alert(NbBundle.getMessage(EjbFreeFormActionProvider.class, "ACTION_debug"), GENERAL_SCRIPT_PATH))
 
173
            return;
 
174
        
 
175
        //let's generate a debug target
 
176
        String propertiesFile = writeDebugProperties();
 
177
        
 
178
        //read script document
 
179
        Document script = readCustomScript(GENERAL_SCRIPT_PATH);
 
180
        if (script == null) //script doesn't exist
 
181
            script = createCustomScript();
 
182
 
 
183
        //append comments and target
 
184
        writeComments(script);
 
185
        writeTargets(script, propertiesFile);
 
186
        
 
187
        //save script
 
188
        writeCustomScript(script, GENERAL_SCRIPT_PATH);
 
189
        
 
190
        //write changes to project.xml
 
191
        addBinding(ActionProvider.COMMAND_DEBUG, GENERAL_SCRIPT_PATH, DEBUG_TARGET, null, null, null, null, null);
 
192
        
 
193
        //show the result
 
194
        jumpToBinding(ActionProvider.COMMAND_DEBUG);
 
195
        jumpToBuildScript(GENERAL_SCRIPT_PATH, DEBUG_TARGET);
 
196
        openFile(propertiesFile);
 
197
    }
 
198
    
 
199
    /**
 
200
     * Display an alert asking the user whether to really generate a target.
 
201
     * @param commandDisplayName the display name of the action to be bound
 
202
     * @param scriptPath the path that to the script that will be generated or written to
 
203
     * @return true if IDE should proceed
 
204
     */
 
205
    private boolean alert(String commandDisplayName, String scriptPath) {
 
206
        String projectDisplayName = ProjectUtils.getInformation(project).getDisplayName();
 
207
        String title = NbBundle.getMessage(EjbFreeFormActionProvider.class, "TITLE_generate_target_dialog", commandDisplayName, projectDisplayName);
 
208
        String body = NbBundle.getMessage(EjbFreeFormActionProvider.class, "TEXT_generate_target_dialog", commandDisplayName, scriptPath);
 
209
        NotifyDescriptor d = new NotifyDescriptor.Message(body, NotifyDescriptor.QUESTION_MESSAGE);
 
210
        d.setTitle(title);
 
211
        d.setOptionType(NotifyDescriptor.OK_CANCEL_OPTION);
 
212
        JButton generate = new JButton(NbBundle.getMessage(EjbFreeFormActionProvider.class, "LBL_generate"));
 
213
        generate.setDefaultCapable(true);
 
214
        d.setOptions(new Object[] {generate, NotifyDescriptor.CANCEL_OPTION});
 
215
        return DialogDisplayer.getDefault().notify(d) == generate;
 
216
    }
 
217
 
 
218
    /**
 
219
     * Reads a generated script if it exists, else create a skeleton.
 
220
     * @param scriptPath e.g. {@link #FILE_SCRIPT_PATH} or {@link #GENERAL_SCRIPT_PATH}
 
221
     * @return script document.
 
222
     */
 
223
    Document readCustomScript(String scriptPath) throws IOException, SAXException {
 
224
 
 
225
        Document script = null;
 
226
        FileObject scriptFile = helper.getProjectDirectory().getFileObject(scriptPath);
 
227
        if (scriptFile != null) {
 
228
            InputStream is = scriptFile.getInputStream();
 
229
            try {
 
230
                script = XMLUtil.parse(new InputSource(is), false, true, null, null);
 
231
            } finally {
 
232
                is.close();
 
233
            }
 
234
        }
 
235
        
 
236
        return script;
 
237
    }
 
238
    
 
239
    /**
 
240
     * Creates custom script.
 
241
     * @return script document.
 
242
     */
 
243
    Document createCustomScript() {
 
244
        //create document, set root and its attributes
 
245
        Document script = XMLUtil.createDocument("project", null, null, null); // NOI18N
 
246
        Element scriptRoot = script.getDocumentElement();
 
247
        scriptRoot.setAttribute("basedir", /* ".." times count('/', FILE_SCRIPT_PATH) */".."); // NOI18N
 
248
        String projname = ProjectUtils.getInformation(project).getDisplayName();
 
249
        scriptRoot.setAttribute("name", NbBundle.getMessage(EjbFreeFormActionProvider.class, "LBL_generated_script_name", projname));
 
250
 
 
251
        //copy properties from project.xml to the script
 
252
        copyProperties(Util.getPrimaryConfigurationData(helper), scriptRoot);
 
253
        
 
254
        return script;
 
255
    }
 
256
 
 
257
    /**
 
258
     * Copies all properties defined in project.xml to Ant syntax.
 
259
     * Used for generated targets which essentially copy Ant fragments from project.xml
 
260
     * (rather than the user's build.xml).
 
261
     * @param config XML of an Ant project (document element)
 
262
     * @param script target custom script
 
263
     */
 
264
    private void copyProperties(Element config, Element script) {
 
265
        // Look for <properties> in project.xml and make corresponding definitions in the Ant script.
 
266
        // See corresponding schema.
 
267
        
 
268
        Element data = Util.getPrimaryConfigurationData(helper);
 
269
        Element properties = Util.findElement(data, "properties", Util.NAMESPACE); // NOI18N
 
270
        if (properties != null) {
 
271
            Iterator/*<Element>*/ propertiesIt = Util.findSubElements(properties).iterator();
 
272
            while (propertiesIt.hasNext()) {
 
273
                Element el = (Element) propertiesIt.next();
 
274
                Element nue = script.getOwnerDocument().createElement("property"); // NOI18N
 
275
                if (el.getLocalName().equals("property")) { // NOI18N
 
276
                    String name = el.getAttribute("name"); // NOI18N
 
277
                    assert name != null;
 
278
                    String text = Util.findText(el);
 
279
                    assert text != null;
 
280
                    nue.setAttribute("name", name); // NOI18N
 
281
                    nue.setAttribute("value", text); // NOI18N
 
282
                } else if (el.getLocalName().equals("property-file")) { // NOI18N
 
283
                    String text = Util.findText(el);
 
284
                    assert text != null;
 
285
                    nue.setAttribute("file", text); // NOI18N
 
286
                } else {
 
287
                    assert false : el;
 
288
                }
 
289
                script.appendChild(nue);
 
290
            }
 
291
        }
 
292
    }
 
293
 
 
294
    /**
 
295
     * Appends the comments to script.
 
296
     * @param script Script to write to.
 
297
     */
 
298
    private void writeComments(Document script) {
 
299
        Comment comm4Edit = script.createComment(" " + NbBundle.getMessage(EjbFreeFormActionProvider.class, "COMMENT_edit_target") + " "); // NOI18N
 
300
        Comment comm4Info = script.createComment(" " + NbBundle.getMessage(EjbFreeFormActionProvider.class, "COMMENT_more_info_debug") + " "); // NOI18N
 
301
 
 
302
        Element scriptRoot = script.getDocumentElement();
 
303
        scriptRoot.appendChild(comm4Edit);
 
304
        scriptRoot.appendChild(comm4Info);
 
305
    }
 
306
    
 
307
    /**
 
308
     * Appends necessary targets to script.
 
309
     * @param script Script to write to.
 
310
     */
 
311
    private void writeTargets(Document script, String propertiesFile) {
 
312
        createLoadPropertiesTarget(script, propertiesFile);
 
313
        createCheckPropertiesTarget(script);
 
314
        createInitTarget(script);
 
315
        createDebugTarget(script);
 
316
    }
 
317
 
 
318
    /**
 
319
     * Creates target:
 
320
     *  <target name="-load-props">
 
321
     *      <property file="nbproject/project.properties"/>
 
322
     *  </target>
 
323
     * @param script Script to write to.
 
324
     */
 
325
    private void createLoadPropertiesTarget(Document script, String propertiesFile) {
 
326
        Element target = script.createElement("target"); // NOI18N
 
327
        target.setAttribute("name", LOAD_PROPS_TARGET); // NOI18N
 
328
        Element property = script.createElement("property"); // NOI18N
 
329
        property.setAttribute("file", propertiesFile);// NOI18N
 
330
        target.appendChild(property);
 
331
        script.getDocumentElement().appendChild(target);
 
332
    }
 
333
    
 
334
    /**
 
335
     * Creates target:
 
336
     * <target name="-check-props">
 
337
     *     <fail unless="jpda.session.name"/>
 
338
     *     <fail unless="jpda.host"/>
 
339
     *     <fail unless="jpda.address"/>
 
340
     *     <fail unless="jpda.transport"/>
 
341
     * </target>
 
342
     * @param script Script to write to.
 
343
     */
 
344
    private void createCheckPropertiesTarget(Document script) {
 
345
        Element target = script.createElement("target"); // NOI18N
 
346
        target.setAttribute("name", CHECK_PROPS_TARGET); // NOI18N
 
347
        Element fail;
 
348
        for (int i = 0; i < DEBUG_PROPERTIES.length; i++) {
 
349
            fail = script.createElement("fail"); // NOI18N
 
350
            fail.setAttribute("unless", DEBUG_PROPERTIES[i]); // NOI18N
 
351
            target.appendChild(fail);
 
352
        }
 
353
        
 
354
        script.getDocumentElement().appendChild(target);
 
355
    }
 
356
    
 
357
    /**
 
358
     * Creates target:
 
359
     * <target name="-init" depends="-load-props, -check-props"/>
 
360
     * @param script Script to write to.
 
361
     */
 
362
    private void createInitTarget(Document script) {
 
363
        Element target = script.createElement("target"); // NOI18N
 
364
        target.setAttribute("name", INIT_TARGET); // NOI18N
 
365
        target.setAttribute("depends", LOAD_PROPS_TARGET + ", " + CHECK_PROPS_TARGET); // NOI18N
 
366
        script.getDocumentElement().appendChild(target);
 
367
    }
 
368
    
 
369
    /**
 
370
     * Creates target:
 
371
     * <target name="debug-nb" depends="-init" if="netbeans.home">
 
372
     *     <nbjpdaconnect name="${session.name}" host="${jpda.host}" address="${jpda.address}" transport="${jpda.transport}"/>
 
373
     * </target>
 
374
     * @param script Script to write to.
 
375
     */
 
376
    private void createDebugTarget(Document script) {
 
377
        Element target = script.createElement("target");
 
378
        target.setAttribute("name", DEBUG_TARGET); // NOI18N
 
379
        target.setAttribute("depends", INIT_TARGET); // NOI18N
 
380
        target.setAttribute("if", "netbeans.home"); // NOI18N
 
381
        Element nbjpdaconnect = script.createElement("nbjpdaconnect"); // NOI18N
 
382
        nbjpdaconnect.setAttribute("name", "${" + EjbFreeformProperties.JPDA_SESSION_NAME + "}"); // NOI18N
 
383
        nbjpdaconnect.setAttribute("host", "${" + EjbFreeformProperties.JPDA_HOST + "}"); // NOI18N
 
384
        nbjpdaconnect.setAttribute("address", "${" + EjbFreeformProperties.JPDA_ADDRESS + "}"); // NOI18N
 
385
        nbjpdaconnect.setAttribute("transport", "${" + EjbFreeformProperties.JPDA_TRANSPORT + "}"); // NOI18N
 
386
        Element sourcepath = script.createElement("sourcepath"); // NOI18N
 
387
        Element path = script.createElement("path"); // NOI18N
 
388
        path.setAttribute("path", "${debug.sourcepath}"); // NOI18N
 
389
        sourcepath.appendChild(path);
 
390
        nbjpdaconnect.appendChild(sourcepath);
 
391
        target.appendChild(nbjpdaconnect);
 
392
        
 
393
        script.getDocumentElement().appendChild(target);
 
394
    }
 
395
 
 
396
    /**
 
397
     * Write a script with a new or modified document.
 
398
     * @param script Document written to the script path.
 
399
     * @param scriptPath e.g. {@link #FILE_SCRIPT_PATH} or {@link #GENERAL_SCRIPT_PATH}
 
400
     */
 
401
    void writeCustomScript(Document script, String scriptPath) throws IOException {
 
402
        FileObject scriptFile = helper.getProjectDirectory().getFileObject(scriptPath);
 
403
        if (scriptFile == null) {
 
404
            scriptFile = FileUtil.createData(helper.getProjectDirectory(), scriptPath);
 
405
        }
 
406
        FileLock lock = scriptFile.lock();
 
407
        try {
 
408
            OutputStream os = scriptFile.getOutputStream(lock);
 
409
            try {
 
410
                XMLUtil.write(script, os, "UTF-8"); // NOI18N
 
411
            } finally {
 
412
                os.close();
 
413
            }
 
414
        } finally {
 
415
            lock.releaseLock();
 
416
        }
 
417
    }
 
418
 
 
419
    /**
 
420
     * Add an action binding to project.xml.
 
421
     * If there is no required context, the action is also added to the context menu of the project node.
 
422
     * @param command the command name
 
423
     * @param scriptPath the path to the generated script
 
424
     * @param target the name of the target (in scriptPath)
 
425
     * @param propertyName a property name to hold the selection (or null for no context, in which case remainder should be null)
 
426
     * @param dir the raw text to use for the directory name
 
427
     * @param pattern the regular expression to match, or null
 
428
     * @param format the format to use
 
429
     * @param separator the separator to use for multiple files, or null for single file only
 
430
     */
 
431
    void addBinding(String command, String scriptPath, String target, String propertyName, String dir, String pattern, String format, String separator) throws IOException {
 
432
        // XXX cannot use FreeformProjectGenerator since that is currently not a public support SPI from ant/freeform
 
433
        // XXX should this try to find an existing binding? probably not, since it is assumed that if there was one, we would never get here to begin with
 
434
        Element data = Util.getPrimaryConfigurationData(helper);
 
435
        Element ideActions = Util.findElement(data, "ide-actions", Util.NAMESPACE); // NOI18N
 
436
        if (ideActions == null) {
 
437
            // Probably won't happen, since generator produces it always.
 
438
            // Not trivial to just add it now, since order is significant in the schema. (FPG deals with these things.)
 
439
            return;
 
440
        }
 
441
        Document doc = data.getOwnerDocument();
 
442
        Element action = doc.createElementNS(Util.NAMESPACE, "action"); // NOI18N
 
443
        action.setAttribute("name", command); // NOI18N
 
444
        Element script = doc.createElementNS(Util.NAMESPACE, "script"); // NOI18N
 
445
        script.appendChild(doc.createTextNode(scriptPath));
 
446
        action.appendChild(script);
 
447
        Element targetEl = doc.createElementNS(Util.NAMESPACE, "target"); // NOI18N
 
448
        targetEl.appendChild(doc.createTextNode(target));
 
449
        action.appendChild(targetEl);
 
450
        ideActions.appendChild(action);
 
451
        
 
452
        if (propertyName != null) {
 
453
            Element context = doc.createElementNS(Util.NAMESPACE, "context"); // NOI18N
 
454
            Element property = doc.createElementNS(Util.NAMESPACE, "property"); // NOI18N
 
455
            property.appendChild(doc.createTextNode(propertyName));
 
456
            context.appendChild(property);
 
457
            Element folder = doc.createElementNS(Util.NAMESPACE, "folder"); // NOI18N
 
458
            folder.appendChild(doc.createTextNode(dir));
 
459
            context.appendChild(folder);
 
460
            if (pattern != null) {
 
461
                Element patternEl = doc.createElementNS(Util.NAMESPACE, "pattern"); // NOI18N
 
462
                patternEl.appendChild(doc.createTextNode(pattern));
 
463
                context.appendChild(patternEl);
 
464
            }
 
465
            Element formatEl = doc.createElementNS(Util.NAMESPACE, "format"); // NOI18N
 
466
            formatEl.appendChild(doc.createTextNode(format));
 
467
            context.appendChild(formatEl);
 
468
            Element arity = doc.createElementNS(Util.NAMESPACE, "arity"); // NOI18N
 
469
            if (separator != null) {
 
470
                Element separatorEl = doc.createElementNS(Util.NAMESPACE, "separated-files"); // NOI18N
 
471
                separatorEl.appendChild(doc.createTextNode(separator));
 
472
                arity.appendChild(separatorEl);
 
473
            } else {
 
474
                arity.appendChild(doc.createElementNS(Util.NAMESPACE, "one-file-only")); // NOI18N
 
475
            }
 
476
            context.appendChild(arity);
 
477
            action.appendChild(context);
 
478
        } else {
 
479
            // Add a context menu item, since it applies to the project as a whole.
 
480
            // Assume there is already a <context-menu> defined, which is quite likely.
 
481
            Element view = Util.findElement(data, "view", Util.NAMESPACE); // NOI18N
 
482
            if (view != null) {
 
483
                Element contextMenu = Util.findElement(view, "context-menu", Util.NAMESPACE); // NOI18N
 
484
                if (contextMenu != null) {
 
485
                    Element ideAction = doc.createElementNS(Util.NAMESPACE, "ide-action"); // NOI18N
 
486
                    ideAction.setAttribute("name", command); // NOI18N
 
487
                    contextMenu.appendChild(ideAction);
 
488
                }
 
489
            }
 
490
        }
 
491
 
 
492
        Util.putPrimaryConfigurationData(helper, data);
 
493
        ProjectManager.getDefault().saveProject(project);
 
494
    }
 
495
    
 
496
    private String writeDebugProperties() throws IOException {
 
497
        String fileName = "debug"; // NOI18N
 
498
        String file;
 
499
        int i = 0;
 
500
        do {
 
501
            file = "nbproject/" + fileName + (i != 0 ? String.valueOf(i) : "") + ".properties"; // NOI18N
 
502
            i++;
 
503
        } while (helper.resolveFileObject(file) != null);
 
504
        FileObject fo = FileUtil.createData(project.getProjectDirectory(), file);
 
505
        FileLock lock = fo.lock();
 
506
        OutputStream out = null;
 
507
        InputStream in = null;
 
508
        try {
 
509
            out = new BufferedOutputStream(fo.getOutputStream(lock));
 
510
            in = EjbFreeFormActionProvider.class.getResourceAsStream(DEBUG_PROPERTIES_TEMPLATE);
 
511
            byte[] buffer = new byte[4096];
 
512
            int read;
 
513
            do {
 
514
                read = in.read(buffer);
 
515
                out.write(buffer, 0, read);
 
516
            } while (read == buffer.length);
 
517
        }
 
518
        finally {
 
519
            if (in != null)
 
520
                in.close();
 
521
            if (out != null)
 
522
                out.close();
 
523
            lock.releaseLock();
 
524
        }
 
525
        
 
526
        // set the generated properties
 
527
        EditableProperties ep = helper.getProperties(file);
 
528
        ProjectInformation pi = ProjectUtils.getInformation(project);
 
529
        ep.setProperty(EjbFreeformProperties.JPDA_SESSION_NAME, pi.getName());
 
530
        ep.setProperty(EjbFreeformProperties.DEBUG_SOURCEPATH, findSourceFolders(JavaProjectConstants.SOURCES_TYPE_JAVA));
 
531
        helper.putProperties(file, ep);
 
532
        
 
533
        return file;
 
534
    }
 
535
 
 
536
    /**
 
537
     * Jump to an action binding in the editor.
 
538
     * @param command an {@link ActionProvider} command name found in project.xml
 
539
     */
 
540
    private void jumpToBinding(String command) {
 
541
        jumpToFile(AntProjectHelper.PROJECT_XML_PATH, command, "action", "name"); // NOI18N
 
542
    }
 
543
 
 
544
    /**
 
545
     * Jump to a target in the editor.
 
546
     * @param scriptPath the script to open
 
547
     * @param target the name of the target (in scriptPath)
 
548
     */
 
549
    private void jumpToBuildScript(String scriptPath, String target) {
 
550
        jumpToFile(scriptPath, target, "target", "name"); // NOI18N
 
551
    }
 
552
    
 
553
    /**
 
554
     * Jump to some line in an XML file.
 
555
     * @param path project-relative path to the file
 
556
     * @param match {@see #findLine}
 
557
     * @param elementLocalName {@see #findLine}
 
558
     * @param elementAttributeName {@see #findLine}
 
559
     */
 
560
    private void jumpToFile(String path, String match, String elementLocalName, String elementAttributeName) {
 
561
        FileObject file = helper.getProjectDirectory().getFileObject(path);
 
562
        if (file == null) {
 
563
            return;
 
564
        }
 
565
        int line;
 
566
        try {
 
567
            line = findLine(file, match, elementLocalName, elementAttributeName);
 
568
        } catch (Exception e) {
 
569
            Logger.getLogger("global").log(Level.INFO, null, e);
 
570
            return;
 
571
        }
 
572
        if (line == -1) {
 
573
            // Just open it.
 
574
            line = 0;
 
575
        }
 
576
        DataObject fileDO;
 
577
        try {
 
578
            fileDO = DataObject.find(file);
 
579
        } catch (DataObjectNotFoundException e) {
 
580
            throw new AssertionError(e);
 
581
        }
 
582
        LineCookie lines = (LineCookie) fileDO.getCookie(LineCookie.class);
 
583
        if (lines != null) {
 
584
            try {
 
585
                lines.getLineSet().getCurrent(line).show(Line.SHOW_GOTO);
 
586
            } catch (IndexOutOfBoundsException e) {
 
587
                // XXX reproducibly thrown if the document was already open. Why?? (file.refresh() above does not help.)
 
588
                Logger.getLogger(EjbFreeFormActionProvider.class.getName()).log(Level.WARNING,
 
589
                        e + " [file=" +file + " match=" + match + " line=" + line + "]"); // NOI18N
 
590
                lines.getLineSet().getCurrent(0).show(Line.SHOW_GOTO);
 
591
            }
 
592
        }
 
593
    }
 
594
    
 
595
    private void openFile(String path) {
 
596
        FileObject file = helper.getProjectDirectory().getFileObject(path);
 
597
        if (file == null)
 
598
            return;
 
599
        
 
600
        DataObject fileDO;
 
601
        try {
 
602
            fileDO = DataObject.find(file);
 
603
        }
 
604
        catch (DataObjectNotFoundException e) {
 
605
            throw new AssertionError(e);
 
606
        }
 
607
        
 
608
        EditCookie edit = (EditCookie)fileDO.getCookie(EditCookie.class);
 
609
        if (edit != null) {
 
610
            edit.edit();
 
611
        }
 
612
    }
 
613
 
 
614
    /**
 
615
     * Find the line number of a target in an Ant script, or some other line in an XML file.
 
616
     * Able to find a certain element with a certain attribute matching a given value.
 
617
     * See also AntTargetNode.TargetOpenCookie.
 
618
     * @param file an Ant script or other XML file
 
619
     * @param match the attribute value to match (e.g. target name)
 
620
     * @param elementLocalName the (local) name of the element to look for
 
621
     * @param elementAttributeName the name of the attribute to match on
 
622
     * @return the line number (0-based), or -1 if not found
 
623
     */
 
624
    static final int findLine(FileObject file, final String match, final String elementLocalName, final String elementAttributeName) throws IOException, SAXException, ParserConfigurationException {
 
625
        InputSource in = new InputSource(file.getURL().toString());
 
626
        SAXParserFactory factory = SAXParserFactory.newInstance();
 
627
        factory.setNamespaceAware(true);
 
628
        SAXParser parser = factory.newSAXParser();
 
629
        final int[] line = new int[] {-1};
 
630
        class Handler extends DefaultHandler {
 
631
            private Locator locator;
 
632
            public void setDocumentLocator(Locator l) {
 
633
                locator = l;
 
634
            }
 
635
            public void startElement(String uri, String localname, String qname, Attributes attr) throws SAXException {
 
636
                if (line[0] == -1) {
 
637
                    if (localname.equals(elementLocalName) && match.equals(attr.getValue(elementAttributeName))) { // NOI18N
 
638
                        line[0] = locator.getLineNumber() - 1;
 
639
                    }
 
640
                }
 
641
            }
 
642
        }
 
643
        parser.parse(in, new Handler());
 
644
        return line[0];
 
645
    }
 
646
    
 
647
    private String findSourceFolders(String type) {
 
648
        StringBuffer result = new StringBuffer();
 
649
        Element data = Util.getPrimaryConfigurationData(helper);
 
650
        Element foldersEl = Util.findElement(data, "folders", Util.NAMESPACE); // NOI18N
 
651
        if (foldersEl != null) {
 
652
            for (Iterator i = Util.findSubElements(foldersEl).iterator(); i.hasNext();) {
 
653
                Element sourceFolderEl = (Element)i.next();
 
654
                Element typeEl = Util.findElement(sourceFolderEl , "type", Util.NAMESPACE); // NOI18N
 
655
                if (typeEl == null || !Util.findText(typeEl).equals(type))
 
656
                    continue;
 
657
                Element locationEl = Util.findElement(sourceFolderEl , "location", Util.NAMESPACE); // NOI18N
 
658
                if (locationEl == null)
 
659
                    continue;
 
660
                String location = Util.findText(locationEl);
 
661
                if (result.length() > 0)
 
662
                    result.append(":"); // NOI18N
 
663
                result.append(location);
 
664
            }
 
665
        }
 
666
        return result.toString();
 
667
    }
 
668
}