This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 237757
Collapse All | Expand All

(-)a/java.api.common/apichanges.xml (+14 lines)
Lines 105-110 Link Here
105
105
106
    <!-- ACTUAL CHANGES BEGIN HERE: -->
106
    <!-- ACTUAL CHANGES BEGIN HERE: -->
107
    <changes>
107
    <changes>
108
        <change id="ProjectOperations">
109
            <api name="java-api-common"/>
110
            <summary>Added <code>ProjectOperations</code> support for project operations in Ant based project.</summary>
111
            <version major="1" minor="65"/>
112
            <date day="29" month="10" year="2013"/>
113
            <author login="tzezula"/>
114
            <compatibility addition="yes"/>
115
            <description>
116
                <p>
117
                   Added <code>ProjectOperations</code> support for project operations in Ant based project..
118
                </p>
119
            </description>
120
            <class package="org.netbeans.modules.java.api.common.project" name="ProjectOperations"/>
121
        </change>
108
        <change id="ProjectConfigurations">
122
        <change id="ProjectConfigurations">
109
            <api name="java-api-common"/>
123
            <api name="java-api-common"/>
110
            <summary>Added <code>ProjectConfigurations</code> support for <code>ProjectConfiguration</code>s in Ant base project.</summary>
124
            <summary>Added <code>ProjectConfigurations</code> support for <code>ProjectConfiguration</code>s in Ant base project.</summary>
(-)a/java.api.common/manifest.mf (-1 / +1 lines)
Lines 1-4 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.netbeans.modules.java.api.common/0
2
OpenIDE-Module: org.netbeans.modules.java.api.common/0
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/api/common/resources/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/api/common/resources/Bundle.properties
4
OpenIDE-Module-Specification-Version: 1.64
4
OpenIDE-Module-Specification-Version: 1.65
(-)a/java.api.common/src/org/netbeans/modules/java/api/common/project/BaseActionProvider.java (-6 / +1 lines)
Lines 382-393 Link Here
382
382
383
    @NonNull
383
    @NonNull
384
    public static String getBuildXmlName (final Project project, PropertyEvaluator evaluator) {
384
    public static String getBuildXmlName (final Project project, PropertyEvaluator evaluator) {
385
        assert project != null;
385
        return CommonProjectUtils.getBuildXmlName(evaluator, null);
386
        String buildScriptPath = evaluator.getProperty(BUILD_SCRIPT);
387
        if (buildScriptPath == null) {
388
            buildScriptPath = GeneratedFilesHelper.BUILD_XML_PATH;
389
        }
390
        return buildScriptPath;
391
    }
386
    }
392
387
393
    public static FileObject getBuildXml (final Project project, PropertyEvaluator evaluator) {
388
    public static FileObject getBuildXml (final Project project, PropertyEvaluator evaluator) {
(-)a/java.api.common/src/org/netbeans/modules/java/api/common/project/Bundle.properties (+3 lines)
Lines 40-42 Link Here
40
ERR_RegenerateProjectFiles=Cannot regenerate project metadata.
40
ERR_RegenerateProjectFiles=Cannot regenerate project metadata.
41
ERR_ProjectReadOnly=The project folder {0} is read-only.
41
ERR_ProjectReadOnly=The project folder {0} is read-only.
42
TXT_DefaultConfig=<default config>
42
TXT_DefaultConfig=<default config>
43
44
#ProjectOperations
45
MSG_OldProjectMetadata=The project is not of the current version.
(-)a/java.api.common/src/org/netbeans/modules/java/api/common/project/ProjectOperations.java (+763 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2013 Sun Microsystems, Inc.
41
 */
42
43
package org.netbeans.modules.java.api.common.project;
44
45
import java.io.File;
46
import java.io.IOException;
47
import java.text.MessageFormat;
48
import java.util.ArrayList;
49
import java.util.Collections;
50
import java.util.HashMap;
51
import java.util.HashSet;
52
import java.util.List;
53
import java.util.Map;
54
import java.util.Properties;
55
import java.util.Set;
56
import java.util.logging.Level;
57
import java.util.logging.Logger;
58
import org.apache.tools.ant.module.api.support.ActionUtils;
59
import org.netbeans.api.annotations.common.NonNull;
60
import org.netbeans.api.annotations.common.NullAllowed;
61
import org.netbeans.api.project.FileOwnerQuery;
62
import org.netbeans.api.project.Project;
63
import org.netbeans.api.project.ProjectInformation;
64
import org.netbeans.api.project.ProjectManager;
65
import org.netbeans.api.project.ProjectUtils;
66
import org.netbeans.modules.java.api.common.SourceRoots;
67
import org.netbeans.modules.java.api.common.ant.UpdateHelper;
68
import org.netbeans.modules.java.api.common.util.CommonProjectUtils;
69
import org.netbeans.spi.project.CopyOperationImplementation;
70
import org.netbeans.spi.project.DataFilesProviderImplementation;
71
import org.netbeans.spi.project.DeleteOperationImplementation;
72
import org.netbeans.spi.project.MoveOrRenameOperationImplementation;
73
import org.netbeans.spi.project.support.ant.AntProjectHelper;
74
import org.netbeans.spi.project.support.ant.EditableProperties;
75
import org.netbeans.spi.project.support.ant.PropertyEvaluator;
76
import org.netbeans.spi.project.support.ant.PropertyUtils;
77
import org.netbeans.spi.project.support.ant.ReferenceHelper;
78
import org.openide.filesystems.FileObject;
79
import org.openide.filesystems.FileSystem;
80
import org.openide.filesystems.FileUtil;
81
import org.openide.util.Exceptions;
82
import org.openide.util.NbBundle;
83
import org.openide.util.Pair;
84
import org.openide.util.Parameters;
85
import org.openide.util.Utilities;
86
87
/**
88
 * Support for default project operations for Ant based project.
89
 * @author Tomas Zezula
90
 * @author Jan Lahoda
91
 * @since 1.65
92
 */
93
public final class ProjectOperations {
94
95
    private static final Logger LOG = Logger.getLogger(ProjectOperations.class.getName());
96
    private static final String TARGET_CLEAN = "clean";
97
98
    private ProjectOperations() {
99
        throw new IllegalStateException("No instance allowed.");    //NOI18N
100
    }
101
102
    /**
103
     * Creates a builder for creating {@link DeleteOperationImplementation},
104
     * {@link MoveOrRenameOperationImplementation}, {@link CopyOperationImplementation}
105
     * implementation.
106
     * @param project the project to create project operations for
107
     * @param eval  the project's {@link PropertyEvaluator}
108
     * @param helper the project's {@link UpdateHelper}
109
     * @param refHelper the project's {@link ReferenceHelper}
110
     * @param sources the project's source roots
111
     * @param tests the project's test roots
112
     * @return a builder for project operations
113
     */
114
    @NonNull
115
    public static ProjectOperationsBuilder createBuilder(
116
        @NonNull final Project project,
117
        @NonNull final PropertyEvaluator eval,
118
        @NonNull final UpdateHelper helper,
119
        @NonNull final ReferenceHelper refHelper,
120
        @NonNull final SourceRoots sources,
121
        @NonNull final SourceRoots tests) {
122
        return new ProjectOperationsBuilder(
123
            project,
124
            eval,
125
            helper,
126
            refHelper,
127
            sources,
128
            tests);
129
    }
130
131
    /**
132
     * Callback for project operations.
133
     * The callback is called before and after each project operation.
134
     * The callback is registered by {@link ProjectOperationsBuilder#setCallback} method.
135
     */
136
    public static interface Callback {
137
        /**
138
         * The type of project operation.
139
         */
140
        enum Operation {
141
            /**
142
             * Project delete.
143
             */
144
            DELETE,
145
            /**
146
             * Project copy.
147
             */
148
            COPY,
149
            /**
150
             * Project move.
151
             */
152
            MOVE,
153
            /**
154
             * Project rename.
155
             */
156
            RENAME;
157
        }
158
159
        /**
160
         * Called at the beginning of the project operation.
161
         * @param operation the operation being performed
162
         */
163
        void beforeOperation(@NonNull final Operation operation);
164
165
        /**
166
         * Called at the end of the project operation.
167
         * @param operation the operation being performed
168
         * @param newName the new project's name or null when not applicable, eg. delete
169
         * @param oldProject the old project or null when not applicable, eg. delete, move, rename
170
         */
171
        void afterOperation(
172
                @NonNull final Operation operation,
173
                @NullAllowed String newName,
174
                @NullAllowed Pair<File,Project> oldProject);
175
    }
176
177
178
    /**
179
     * The builder for projects operations.
180
     */
181
    public static final class ProjectOperationsBuilder {
182
183
        private final Project project;
184
        private final PropertyEvaluator eval;
185
        private final UpdateHelper helper;
186
        private final ReferenceHelper refHelper;
187
        private final SourceRoots sources;
188
        private final SourceRoots tests;
189
        private final List<String> additionalMetadataFiles;
190
        private final List<String> additionalDataFiles;
191
        private final List<String> cleanTargets;
192
        private final Set<String> privateProps;
193
        private final Map<String,Pair<String,Boolean>> updatedProps;
194
        private Callback callback;
195
        private String buildScriptProperty = ProjectProperties.BUILD_SCRIPT;
196
197
        private ProjectOperationsBuilder(
198
            @NonNull final Project project,
199
            @NonNull final PropertyEvaluator eval,
200
            @NonNull final UpdateHelper helper,
201
            @NonNull final ReferenceHelper refHelper,
202
            @NonNull final SourceRoots sources,
203
            @NonNull final SourceRoots tests) {
204
            Parameters.notNull("project", project); //NOI18N
205
            Parameters.notNull("eval", eval);   //NOI18N
206
            Parameters.notNull("helper", helper);   //NOI18N
207
            Parameters.notNull("refHelper", refHelper); //NOI18N
208
            Parameters.notNull("sources", sources); //NOI18N
209
            Parameters.notNull("tests", tests); //NOI18N
210
            this.project = project;
211
            this.eval = eval;
212
            this.helper = helper;
213
            this.refHelper = refHelper;
214
            this.sources = sources;
215
            this.tests = tests;
216
            this.additionalMetadataFiles = new ArrayList<>();
217
            this.additionalDataFiles = new ArrayList<>();
218
            this.cleanTargets = new ArrayList<>();            
219
            this.privateProps = new HashSet<>();
220
            this.updatedProps = new HashMap<>();
221
        }
222
223
        /**
224
         * Sets the name of property referencing the project build script.
225
         * @param propertyName the name of property holding the name of project's build script.
226
         * @return the {@link ProjectOperationsBuilder}
227
         */
228
        @NonNull
229
        public ProjectOperationsBuilder setBuildScriptProperty(@NonNull final String propertyName) {
230
            Parameters.notNull("propertyName", propertyName);   //NOI18N
231
            this.buildScriptProperty = propertyName;
232
            return this;
233
        }
234
235
        /**
236
         * Adds build script targets to the list of clean targets.
237
         * All the added targets are executed before project operation, when no
238
         * clean target is set the default one "clean" is used.
239
         * @param cleanTargets the clean targets
240
         * @return the {@link ProjectOperationsBuilder}
241
         */
242
        @NonNull
243
        public ProjectOperationsBuilder addCleanTargets(@NonNull String... cleanTargets) {
244
            Parameters.notNull("cleanTargets", cleanTargets);   //NOI18N
245
            Collections.addAll(this.cleanTargets, cleanTargets);
246
            return this;
247
        }
248
249
        /**
250
         * Adds additional files to the list of project metadata.
251
         * The "nbproject" and project build script are already included.
252
         * @param paths the metadata file paths, relative to project directory
253
         * @return the {@link ProjectOperationsBuilder}
254
         */
255
        @NonNull
256
        public ProjectOperationsBuilder addMetadataFiles(@NonNull final String... paths) {
257
            Parameters.notNull("paths", paths);   //NOI18N
258
            Collections.addAll(additionalMetadataFiles, paths);
259
            return this;
260
        }
261
262
        /**
263
         * Adds additional files to the list of project data files.
264
         * The source roots, test roots and library definitions are already included.
265
         * @param paths the data file paths, relative to project directory
266
         * @return the {@link ProjectOperationsBuilder}
267
         */
268
        @NonNull
269
        public ProjectOperationsBuilder addDataFiles(@NonNull final String... paths) {
270
            Parameters.notNull("paths", paths);   //NOI18N
271
            Collections.addAll(additionalDataFiles, paths);
272
            return this;
273
        }
274
275
        /**
276
         * Adds private properties which should be retained during copy, move or rename of project.
277
         * @param properties the private properties to be retained
278
         * @return the {@link ProjectOperationsBuilder}
279
         */
280
        @NonNull
281
        public ProjectOperationsBuilder addPreservedPrivateProperties(@NonNull final String... properties) {
282
            Parameters.notNull("properties", properties);   //NOI18N
283
            Collections.addAll(privateProps, properties);
284
            return this;
285
        }
286
287
        /**
288
         * Adds a project property which should be updated by a new project name after rename or copy of project.
289
         * @param propertyName  the project property name
290
         * @param propertyPattern the {@link MessageFormat} pattern of the property value, the "{0}"
291
         * is replaced by the new project name
292
         * @param antName when true the project name is converted into Ant friendly name before substitution
293
         * @return the {@link ProjectOperationsBuilder}
294
         */
295
        @NonNull
296
        public ProjectOperationsBuilder addUpdatedNameProperty(
297
                @NonNull final String propertyName,
298
                @NullAllowed String propertyPattern,
299
                final boolean antName) {
300
            Parameters.notNull("propertyName", propertyName);  //NOI18N
301
            if (propertyPattern == null) {
302
                propertyPattern = "{0}";    //NOI18N
303
            }
304
            updatedProps.put(propertyName, Pair.<String,Boolean>of(propertyPattern, antName));
305
            return this;
306
        }
307
308
        /**
309
         * Sets the project operation callback.
310
         * @param callback the callback
311
         * @return the {@link ProjectOperationsBuilder}
312
         */
313
        @NonNull
314
        public ProjectOperationsBuilder setCallback(@NonNull final Callback callback) {
315
            Parameters.notNull("callback", callback);   //NOI18N
316
            this.callback = callback;
317
            return this;
318
        }
319
320
        /**
321
         * Creates a new configured {@link CopyOperationImplementation},
322
         * {@link DeleteOperationImplementation} and {@link MoveOrRenameOperationImplementation}
323
         * instance.
324
         * @return the project operations implementation
325
         */
326
        @NonNull
327
        public DataFilesProviderImplementation build() {
328
            if (cleanTargets.isEmpty()) {
329
                cleanTargets.add(TARGET_CLEAN);
330
            }
331
            return new Operations(
332
                project,
333
                eval,
334
                helper,
335
                refHelper,
336
                sources,
337
                tests,
338
                buildScriptProperty,
339
                additionalMetadataFiles,
340
                additionalDataFiles,
341
                cleanTargets,
342
                privateProps,
343
                updatedProps,
344
                callback);
345
        }
346
    }
347
348
349
    private static class Operations implements DataFilesProviderImplementation,
350
            DeleteOperationImplementation,
351
            CopyOperationImplementation, MoveOrRenameOperationImplementation {
352
353
        private final Project project;
354
        private final PropertyEvaluator eval;
355
        private final UpdateHelper helper;
356
        private final ReferenceHelper refHelper;
357
        private final SourceRoots sources;
358
        private final SourceRoots tests;
359
        private final String buildScriptProperty;
360
        private final List<? extends String> additionalMetadataFiles;
361
        private final List<? extends String> additionalDataFiles;
362
        private final List<? extends String> cleanTargets;
363
        private final Set<? extends String> privateProps;
364
        private final Map<String,Pair<String,Boolean>> updatedProps;
365
        private final Callback callback;
366
367
368
        //RELY: Valid only on original project after the notifyMoving or notifyCopying was called
369
        private final Map<String,String> privatePropsToRestore = new HashMap<>();
370
        //RELY: Valid only on original project after the notifyMoving or notifyCopying was called
371
        private String absolutesRelPath;
372
        //RELY: Valid only on original project after the notifyMoving or notifyCopying was called
373
        private String libraryPath;
374
        //RELY: Valid only on original project after the notifyMoving or notifyCopying was called
375
        private File libraryFile;
376
        //RELY: Valid only on original project after the notifyMoving or notifyCopying was called
377
        private boolean libraryWithinProject;
378
        //RELY: Valid only on original project after the notifyMoving or notifyCopying was called
379
        private FileSystem configs;
380
381
        Operations(
382
            @NonNull final Project project,
383
            @NonNull final PropertyEvaluator eval,
384
            @NonNull final UpdateHelper helper,
385
            @NonNull final ReferenceHelper refHelper,
386
            @NonNull final SourceRoots sources,
387
            @NonNull final SourceRoots tests,
388
            @NonNull final String buildScriptProperty,
389
            @NonNull final List<? extends String> additionalMetadataFiles,
390
            @NonNull final List<? extends String> additionalDataFiles,
391
            @NonNull final List<? extends String> cleanTargets,
392
            @NonNull final Set<? extends String> privateProps,
393
            @NonNull final Map<String,Pair<String,Boolean>> updatedProps,
394
            @NullAllowed final Callback callback) {
395
            Parameters.notNull("project", project); //NOI18N
396
            Parameters.notNull("eval", eval);   //NOI18N
397
            Parameters.notNull("helper", helper);   //NOI18N
398
            Parameters.notNull("refHelper", refHelper); //NOI18N
399
            Parameters.notNull("sources", sources); //NOI18N
400
            Parameters.notNull("tests", tests); //NOI18N
401
            Parameters.notNull("buildScriptProperty", buildScriptProperty); //NOI18N
402
            Parameters.notNull("additionalMetadataFiles", additionalMetadataFiles); //NOI18N
403
            Parameters.notNull("additionalDataFiles", additionalDataFiles); //NOI18N
404
            Parameters.notNull("cleanTargets", cleanTargets);   //NOI18N
405
            Parameters.notNull("privateProps", privateProps);   //NOI18N
406
            Parameters.notNull("updatedProps", updatedProps);   //NOI18N
407
            this.project = project;
408
            this.eval = eval;
409
            this.helper = helper;
410
            this.refHelper = refHelper;
411
            this.sources = sources;
412
            this.tests = tests;
413
            this.buildScriptProperty = buildScriptProperty;
414
            this.additionalMetadataFiles = additionalMetadataFiles;
415
            this.additionalDataFiles = additionalDataFiles;
416
            this.cleanTargets = cleanTargets;
417
            this.privateProps = privateProps;
418
            this.updatedProps = updatedProps;
419
            this.callback = callback;
420
        }
421
422
        @Override
423
        public void notifyDeleting() throws IOException {
424
            before(Callback.Operation.DELETE);
425
            clean();
426
        }
427
428
        @Override
429
        public void notifyDeleted() throws IOException {
430
            helper.getAntProjectHelper().notifyDeleted();
431
            after(Callback.Operation.DELETE, null, null);
432
        }
433
434
        @Override
435
        public List<FileObject> getMetadataFiles() {
436
            final FileObject projectDirectory = project.getProjectDirectory();
437
            final List<FileObject> files = new ArrayList<>();
438
            addFile(projectDirectory, "nbproject", files); // NOI18N
439
            addFile(projectDirectory, CommonProjectUtils.getBuildXmlName(eval, buildScriptProperty), files);
440
            for (String amf : additionalMetadataFiles) {
441
                addFile(projectDirectory, amf, files);
442
            }
443
            return files;
444
        }
445
446
        @Override
447
        public List<FileObject> getDataFiles() {
448
            final FileObject projectDirectory = project.getProjectDirectory();
449
            final List<FileObject> files = new ArrayList<>();
450
            //add source & test roots
451
            Collections.addAll(files, sources.getRoots());
452
            Collections.addAll(files, tests.getRoots());
453
            // add libraries folder if it is within project:
454
            final AntProjectHelper aph = helper.getAntProjectHelper();
455
            if (aph.getLibrariesLocation() != null) {
456
                File f = aph.resolveFile(aph.getLibrariesLocation());
457
                if (f != null && f.exists()) {
458
                    FileObject libFolder = FileUtil.toFileObject(f).getParent();
459
                    if (FileUtil.isParentOf(projectDirectory, libFolder)) {
460
                        files.add(libFolder);
461
                    }
462
                }
463
            }
464
            //add additional files
465
            for (String adf : additionalDataFiles) {
466
                addFile(projectDirectory, adf, files);
467
            }
468
            return files;
469
        }
470
471
        @Override
472
        public void notifyCopying() throws IOException {
473
            before(Callback.Operation.COPY);
474
            rememberLibraryLocation();
475
            readPrivateProperties();
476
            rememberConfigurations();
477
        }
478
479
        @Override
480
        public void notifyCopied(Project original, File originalPath, String nueName) throws IOException {
481
            if (original == null) {
482
                //do nothing for the original project.
483
                return ;
484
            }
485
            final Operations origOperations = original.getLookup().lookup(Operations.class);
486
            fixLibraryLocation(origOperations);
487
            fixPrivateProperties(origOperations);
488
            updateProjectProperties(nueName);
489
            refHelper.fixReferences(originalPath);
490
            restoreConfigurations(origOperations);
491
            after(Callback.Operation.COPY, nueName, null);
492
        }
493
494
        @Override
495
        public void notifyRenaming() throws IOException {
496
            if (!this.helper.requestUpdate()) {
497
                throw new IOException(NbBundle.getMessage(
498
                    ProjectOperations.class,
499
                    "MSG_OldProjectMetadata"));
500
            }
501
            before(Callback.Operation.RENAME);
502
            clean();
503
        }
504
505
        @Override
506
        public void notifyRenamed(String nueName) throws IOException {
507
            updateProjectProperties(nueName);
508
            after(Callback.Operation.RENAME, nueName, null);
509
        }
510
511
        @Override
512
        public void notifyMoving() throws IOException {
513
            if (!this.helper.requestUpdate()) {
514
            throw new IOException (NbBundle.getMessage(
515
                ProjectOperations.class,
516
                "MSG_OldProjectMetadata"));
517
            }
518
            before(Callback.Operation.MOVE);
519
            rememberLibraryLocation();
520
            readPrivateProperties ();
521
            rememberConfigurations();
522
            clean();
523
        }
524
525
        @Override
526
        public void notifyMoved(Project original, File originalPath, String nueName) throws IOException {
527
            if (original == null) {
528
                helper.getAntProjectHelper().notifyDeleted();
529
                return ;
530
            }
531
            final Operations origOperations = original.getLookup().lookup(Operations.class);
532
            fixLibraryLocation(origOperations);
533
            fixPrivateProperties (origOperations);
534
            updateProjectProperties(nueName);
535
            refHelper.fixReferences(originalPath);
536
            restoreConfigurations(origOperations);
537
            after(Callback.Operation.MOVE, nueName, Pair.<File, Project>of(originalPath,original));
538
        }
539
540
        private void clean() throws IOException {
541
            final Properties p = new Properties();
542
            final String buildXmlName = CommonProjectUtils.getBuildXmlName(eval, buildScriptProperty);
543
            final FileObject buildXML = project.getProjectDirectory().getFileObject(buildXmlName);
544
            if (buildXML != null) {
545
                ActionUtils.runTarget(
546
                    buildXML,
547
                    cleanTargets.toArray(new String[cleanTargets.size()]),
548
                    p).waitFinished();
549
            } else {
550
                LOG.log(
551
                    Level.INFO,
552
                    "Not cleaning the project: {0}, the build file: {1} does not exist.", //NOI18N
553
                    new Object[] {
554
                        ProjectUtils.getInformation(project).getDisplayName(),
555
                        buildXmlName
556
                    });
557
            }
558
        }
559
560
        private void rememberLibraryLocation() {
561
            libraryWithinProject = false;
562
            absolutesRelPath = null;
563
            libraryPath = helper.getAntProjectHelper().getLibrariesLocation();
564
            if (libraryPath != null) {
565
                File prjRoot = FileUtil.toFile(project.getProjectDirectory());
566
                libraryFile = PropertyUtils.resolveFile(prjRoot, libraryPath);
567
                if (FileOwnerQuery.getOwner(Utilities.toURI(libraryFile)) == project &&
568
                        libraryFile.getAbsolutePath().startsWith(prjRoot.getAbsolutePath())) {
569
                    //do not update the relative path if within the project..
570
                    libraryWithinProject = true;
571
                    FileObject fo = FileUtil.toFileObject(libraryFile);
572
                    if (new File(libraryPath).isAbsolute() && fo != null) {
573
                        // if absolte path within project, it will get moved/copied..
574
                        absolutesRelPath = FileUtil.getRelativePath(project.getProjectDirectory(), fo);
575
                    }
576
                }
577
            }
578
        }
579
580
        private void readPrivateProperties () {
581
            ProjectManager.mutex().readAccess(new Runnable() {
582
                public void run () {
583
                    privatePropsToRestore.clear();
584
                    for (String privateProp : privateProps) {
585
                        backUpPrivateProp(privateProp);
586
                    }
587
                }
588
            });
589
        }
590
        //where
591
        /**
592
         * Threading: Has to be called under project mutex
593
         */
594
        private void backUpPrivateProp(String propName) {
595
            assert ProjectManager.mutex().isReadAccess() || ProjectManager.mutex().isWriteAccess();
596
            final String tmp = helper.getProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH).getProperty(propName);
597
            if (tmp != null) {
598
                privatePropsToRestore.put(propName, tmp);
599
            }
600
        }
601
602
        private void rememberConfigurations () {
603
            FileObject fo = project.getProjectDirectory().getFileObject(ProjectConfigurations.CONFIG_PROPS_PATH);
604
            if (fo != null) {
605
                //Has configurations
606
                try {
607
                    FileSystem fs = FileUtil.createMemoryFileSystem();
608
                    FileUtil.copyFile(fo, fs.getRoot(),fo.getName());
609
                    fo = project.getProjectDirectory().getFileObject("nbproject/private/configs");      //NOI18N
610
                    if (fo != null && fo.isFolder()) {
611
                        FileObject cfgs = fs.getRoot().createFolder("configs");                         //NOI18N
612
                        for (FileObject child : fo.getChildren()) {
613
                            FileUtil.copyFile(child, cfgs, child.getName());
614
                        }
615
                    }
616
                    configs = fs;
617
                } catch (IOException ioe) {
618
                    Exceptions.printStackTrace(ioe);
619
                }
620
            }
621
        }
622
623
        private void fixLibraryLocation(Operations original) throws IllegalArgumentException {
624
            String libPath = original.libraryPath;
625
            if (libPath != null) {
626
                if (!new File(libPath).isAbsolute()) {
627
                    //relative path to libraries
628
                    if (!original.libraryWithinProject) {
629
                        File file = original.libraryFile;
630
                        if (file == null) {
631
                            // could happen in some rare cases, but in that case the original project was already broken, don't fix.
632
                            return;
633
                        }
634
                        String relativized = PropertyUtils.relativizeFile(FileUtil.toFile(project.getProjectDirectory()), file);
635
                        if (relativized != null) {
636
                            helper.getAntProjectHelper().setLibrariesLocation(relativized);
637
                        } else {
638
                            //cannot relativize, use absolute path
639
                            helper.getAntProjectHelper().setLibrariesLocation(file.getAbsolutePath());
640
                        }
641
                    } else {
642
                        //got copied over to new location.. the relative path is the same..
643
                    }
644
                } else {
645
646
                    //absolute path to libraries..
647
                    if (original.libraryWithinProject) {
648
                        if (original.absolutesRelPath != null) {
649
                            helper.getAntProjectHelper().setLibrariesLocation(PropertyUtils.resolveFile(FileUtil.toFile(project.getProjectDirectory()), original.absolutesRelPath).getAbsolutePath());
650
                        }
651
                    } else {
652
                        // absolute path to an external folder stays the same.
653
                    }
654
                }
655
            }
656
        }
657
658
        private void fixPrivateProperties (final Operations original) {
659
            if (original != null && !original.privatePropsToRestore.isEmpty()) {
660
                ProjectManager.mutex().writeAccess(new Runnable () {
661
                    public void run () {
662
                        final EditableProperties ep = helper.getProperties (AntProjectHelper.PRIVATE_PROPERTIES_PATH);
663
                        for (Map.Entry<String,String> entry : original.privatePropsToRestore.entrySet()) {
664
                            ep.put(entry.getKey(), entry.getValue());
665
                        }
666
                        helper.putProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH, ep);
667
                    }
668
                });
669
            }
670
        }
671
672
        private void restoreConfigurations (final Operations original) {
673
            final FileSystem fs = original.configs;
674
            original.configs = null;
675
            if (fs != null) {
676
                try {
677
                    FileObject fo = fs.getRoot().getFileObject("config.properties");        //NOI18N
678
                    if (fo != null) {
679
                        FileObject privateFolder = FileUtil.createFolder(project.getProjectDirectory(), "nbproject/private");  //NOI18N
680
                        if (privateFolder != null) {
681
                            // #131857: SyncFailedException : check for file existence before FileUtil.copyFile
682
                            FileObject oldFile = privateFolder.getFileObject(fo.getName(), fo.getExt());
683
                            if (oldFile != null) {
684
                                //Probably delete outside of IDE + move. First try to repair FS cache
685
                                privateFolder.refresh();
686
                                oldFile = privateFolder.getFileObject(fo.getName(), fo.getExt());
687
                                if (oldFile != null) {
688
                                    //The file still exists, delete it.
689
                                    oldFile.delete();
690
                                }
691
                            }
692
693
                            FileUtil.copyFile(fo, privateFolder, fo.getName());
694
                        }
695
                    }
696
                    fo = fs.getRoot().getFileObject("configs");                             //NOI18N
697
                    if (fo != null) {
698
                        FileObject configsFolder = FileUtil.createFolder(project.getProjectDirectory(), "nbproject/private/configs");  //NOI18N
699
                        if (configsFolder != null) {
700
                            for (FileObject child : fo.getChildren()) {
701
                                FileUtil.copyFile(child, configsFolder, child.getName());
702
                            }
703
                        }
704
                    }
705
                } catch (IOException ioe) {
706
                    Exceptions.printStackTrace(ioe);
707
                }
708
            }
709
        }
710
711
        private void updateProjectProperties(@NonNull final String newName) {
712
            if (!updatedProps.isEmpty()) {
713
                final ProjectInformation pi = ProjectUtils.getInformation(project);
714
                final String oldName = pi.getDisplayName();
715
                final EditableProperties ep = helper.getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH);
716
                for (Map.Entry<String,Pair<String,Boolean>> e : updatedProps.entrySet()) {
717
                    final String propName = e.getKey();
718
                    final String format = e.getValue().first();
719
                    final boolean antName = e.getValue().second();
720
                    final String oldProp = MessageFormat.format(
721
                        format,
722
                        antName ?
723
                            PropertyUtils.getUsablePropertyName(oldName) :
724
                            oldName);
725
                    final String propValue = ep.getProperty(propName);
726
                    if (oldProp.equals (propValue)) {
727
                        final String newProp = MessageFormat.format(
728
                            format,
729
                            antName ?
730
                                PropertyUtils.getUsablePropertyName(newName) :
731
                                newName);
732
                        ep.put (propName, newProp);
733
                    }
734
                }
735
                helper.putProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH,ep);
736
            }
737
        }
738
739
        private void before(@NonNull final Callback.Operation operation) {
740
            if (callback != null) {
741
                callback.beforeOperation(operation);
742
            }
743
        }
744
745
        private void after(
746
            @NonNull final Callback.Operation operation,
747
            @NullAllowed final String newName,
748
            @NullAllowed final Pair<File,Project> oldProject) {
749
            if (callback != null) {
750
                callback.afterOperation(operation, newName, oldProject);
751
            }
752
        }
753
754
        private static void addFile(FileObject projectDirectory, String fileName, List<FileObject> result) {
755
            final FileObject file = projectDirectory.getFileObject(fileName);
756
            if (file != null) {
757
                result.add(file);
758
            }
759
        }
760
761
    }
762
763
}
(-)a/java.api.common/src/org/netbeans/modules/java/api/common/util/CommonProjectUtils.java (+23 lines)
Lines 59-67 Link Here
59
import org.netbeans.api.java.source.ClasspathInfo;
59
import org.netbeans.api.java.source.ClasspathInfo;
60
import org.netbeans.api.java.source.ElementHandle;
60
import org.netbeans.api.java.source.ElementHandle;
61
import org.netbeans.api.java.source.SourceUtils;
61
import org.netbeans.api.java.source.SourceUtils;
62
import org.netbeans.modules.java.api.common.project.ProjectProperties;
62
import org.netbeans.modules.java.api.common.project.ui.customizer.MainClassChooser;
63
import org.netbeans.modules.java.api.common.project.ui.customizer.MainClassChooser;
63
import org.netbeans.spi.project.libraries.LibraryImplementation3;
64
import org.netbeans.spi.project.libraries.LibraryImplementation3;
64
import org.netbeans.spi.project.libraries.support.LibrariesSupport;
65
import org.netbeans.spi.project.libraries.support.LibrariesSupport;
66
import org.netbeans.spi.project.support.ant.GeneratedFilesHelper;
67
import org.netbeans.spi.project.support.ant.PropertyEvaluator;
65
import org.openide.filesystems.FileObject;
68
import org.openide.filesystems.FileObject;
66
import org.openide.util.Parameters;
69
import org.openide.util.Parameters;
67
70
Lines 167-172 Link Here
167
    }
170
    }
168
171
169
    /**
172
    /**
173
     * Returns the name of the project's build script.
174
     * @param eval the project's {@link PropertyEvaluator}
175
     * @param propName the name of property holding the reference to project build
176
     * script or null. In case of null the {@link ProjectProperties#BUILD_SCRIPT} is used.
177
     * @return the name of project build script
178
     * @since 1.65
179
     */
180
    @NonNull
181
    public static String getBuildXmlName(
182
        @NonNull final PropertyEvaluator eval,
183
        @NullAllowed final String propName) {
184
        String buildScriptPath = eval.getProperty(
185
                propName != null ? propName : ProjectProperties.BUILD_SCRIPT);
186
        if (buildScriptPath == null || buildScriptPath.isEmpty()) {
187
            buildScriptPath = GeneratedFilesHelper.BUILD_XML_PATH;
188
        }
189
        return buildScriptPath;
190
    }
191
192
    /**
170
     * Creates a {@link LibraryImplementation3} that can subsequently be used with
193
     * Creates a {@link LibraryImplementation3} that can subsequently be used with
171
     * both Ant and Maven based Java projects.
194
     * both Ant and Maven based Java projects.
172
     * @param classpath local library classpath for use by Ant
195
     * @param classpath local library classpath for use by Ant
(-)a/java.j2seproject/nbproject/project.xml (-1 / +1 lines)
Lines 142-148 Link Here
142
                    <compile-dependency/>
142
                    <compile-dependency/>
143
                    <run-dependency>
143
                    <run-dependency>
144
                        <release-version>0-1</release-version>
144
                        <release-version>0-1</release-version>
145
                        <specification-version>1.64</specification-version>
145
                        <specification-version>1.65</specification-version>
146
                    </run-dependency>
146
                    </run-dependency>
147
                </dependency>
147
                </dependency>
148
                <dependency>
148
                <dependency>
(-)a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/AntTargetsProvider.java (-57 lines)
Lines 1-57 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2011 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.modules.java.j2seproject;
43
44
import java.util.Properties;
45
import org.netbeans.api.annotations.common.CheckForNull;
46
import org.netbeans.api.annotations.common.NonNull;
47
import org.openide.util.Lookup;
48
49
/**
50
 * Provides Ant target names for given command.
51
 * Todo: Move to java.common.api if someone else needs it
52
 * @author Tomas Zezula
53
 */
54
public interface AntTargetsProvider {
55
    @CheckForNull
56
    String[] getTargetNames(@NonNull String command, @NonNull Lookup context, @NonNull Properties p, boolean doJavaChecks);
57
}
(-)a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/Bundle.properties (-2 lines)
Lines 82-89 Link Here
82
CTL_UpdateOption=Upgrade Project
82
CTL_UpdateOption=Upgrade Project
83
AD_UpdateOption=N/A
83
AD_UpdateOption=N/A
84
84
85
#J2SEProjectOperations
86
MSG_OldProjectMetadata=The project is not of the current version.
87
85
88
CopyLibs=CopyLibs Task
86
CopyLibs=CopyLibs Task
89
87
(-)a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEActionProvider.java (-1 / +1 lines)
Lines 75-81 Link Here
75
/** Action provider of the J2SE project. This is the place where to do
75
/** Action provider of the J2SE project. This is the place where to do
76
 * strange things to J2SE actions. E.g. compile-single.
76
 * strange things to J2SE actions. E.g. compile-single.
77
 */
77
 */
78
public class J2SEActionProvider extends BaseActionProvider implements AntTargetsProvider {
78
public class J2SEActionProvider extends BaseActionProvider {
79
79
80
    private static final Logger LOG = Logger.getLogger(J2SEActionProvider.class.getName());
80
    private static final Logger LOG = Logger.getLogger(J2SEActionProvider.class.getName());
81
81
(-)a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java (-4 / +39 lines)
Lines 72-77 Link Here
72
import javax.xml.parsers.ParserConfigurationException;
72
import javax.xml.parsers.ParserConfigurationException;
73
import org.netbeans.api.annotations.common.CheckForNull;
73
import org.netbeans.api.annotations.common.CheckForNull;
74
import org.netbeans.api.annotations.common.NonNull;
74
import org.netbeans.api.annotations.common.NonNull;
75
import org.netbeans.api.annotations.common.NullAllowed;
75
import org.netbeans.api.java.classpath.ClassPath;
76
import org.netbeans.api.java.classpath.ClassPath;
76
import org.netbeans.api.java.platform.JavaPlatform;
77
import org.netbeans.api.java.platform.JavaPlatform;
77
import org.netbeans.api.java.project.JavaProjectConstants;
78
import org.netbeans.api.java.project.JavaProjectConstants;
Lines 91-102 Link Here
91
import org.netbeans.modules.java.api.common.classpath.ClassPathProviderImpl;
92
import org.netbeans.modules.java.api.common.classpath.ClassPathProviderImpl;
92
import org.netbeans.modules.java.api.common.project.ProjectConfigurations;
93
import org.netbeans.modules.java.api.common.project.ProjectConfigurations;
93
import org.netbeans.modules.java.api.common.project.ProjectHooks;
94
import org.netbeans.modules.java.api.common.project.ProjectHooks;
95
import org.netbeans.modules.java.api.common.project.ProjectOperations;
94
import org.netbeans.modules.java.api.common.project.ProjectProperties;
96
import org.netbeans.modules.java.api.common.project.ProjectProperties;
95
import org.netbeans.modules.java.api.common.project.ui.LogicalViewProviders;
97
import org.netbeans.modules.java.api.common.project.ui.LogicalViewProviders;
96
import org.netbeans.modules.java.api.common.queries.QuerySupport;
98
import org.netbeans.modules.java.api.common.queries.QuerySupport;
97
import org.netbeans.modules.java.j2seproject.api.J2SEPropertyEvaluator;
99
import org.netbeans.modules.java.j2seproject.api.J2SEPropertyEvaluator;
98
import org.netbeans.modules.java.j2seproject.ui.customizer.CustomizerProviderImpl;
100
import org.netbeans.modules.java.j2seproject.ui.customizer.CustomizerProviderImpl;
99
import org.netbeans.modules.java.j2seproject.ui.customizer.J2SECompositePanelProvider;
101
import org.netbeans.modules.java.j2seproject.ui.customizer.J2SECompositePanelProvider;
102
import org.netbeans.modules.java.j2seproject.ui.customizer.J2SEProjectProperties;
100
import org.netbeans.modules.project.ui.spi.TemplateCategorySorter;
103
import org.netbeans.modules.project.ui.spi.TemplateCategorySorter;
101
import org.netbeans.spi.java.project.support.ExtraSourceJavadocSupport;
104
import org.netbeans.spi.java.project.support.ExtraSourceJavadocSupport;
102
import org.netbeans.spi.java.project.support.LookupMergerSupport;
105
import org.netbeans.spi.java.project.support.LookupMergerSupport;
Lines 110-116 Link Here
110
import org.netbeans.spi.project.support.ant.AntBasedProjectRegistration;
113
import org.netbeans.spi.project.support.ant.AntBasedProjectRegistration;
111
import org.netbeans.spi.project.support.ant.AntProjectHelper;
114
import org.netbeans.spi.project.support.ant.AntProjectHelper;
112
import org.netbeans.spi.project.support.ant.EditableProperties;
115
import org.netbeans.spi.project.support.ant.EditableProperties;
113
import org.netbeans.spi.project.support.ant.FilterPropertyProvider;
114
import org.netbeans.spi.project.support.ant.GeneratedFilesHelper;
116
import org.netbeans.spi.project.support.ant.GeneratedFilesHelper;
115
import org.netbeans.spi.project.support.ant.PropertyEvaluator;
117
import org.netbeans.spi.project.support.ant.PropertyEvaluator;
116
import org.netbeans.spi.project.support.ant.PropertyProvider;
118
import org.netbeans.spi.project.support.ant.PropertyProvider;
Lines 140-145 Link Here
140
import org.openide.loaders.DataObject;
142
import org.openide.loaders.DataObject;
141
import org.openide.modules.SpecificationVersion;
143
import org.openide.modules.SpecificationVersion;
142
import org.openide.util.HelpCtx;
144
import org.openide.util.HelpCtx;
145
import org.openide.util.Pair;
143
/**
146
/**
144
 * Represents one plain J2SE project.
147
 * Represents one plain J2SE project.
145
 * @author Jesse Glick, et al.
148
 * @author Jesse Glick, et al.
Lines 221-227 Link Here
221
224
222
        this.cpProvider = new ClassPathProviderImpl(this.helper, evaluator(), getSourceRoots(),getTestSourceRoots()); //Does not use APH to get/put properties/cfgdata
225
        this.cpProvider = new ClassPathProviderImpl(this.helper, evaluator(), getSourceRoots(),getTestSourceRoots()); //Does not use APH to get/put properties/cfgdata
223
        this.cpMod = new ClassPathModifier(this, this.updateHelper, evaluator(), refHelper, null, createClassPathModifierCallback(), null);
226
        this.cpMod = new ClassPathModifier(this, this.updateHelper, evaluator(), refHelper, null, createClassPathModifierCallback(), null);
224
        lookup = createLookup(aux, new J2SEProjectOperations(this, updateProject));
227
        lookup = createLookup(aux, newProjectOperationsCallback(this, updateProject));
225
    }
228
    }
226
229
227
    private ClassPathModifier.Callback createClassPathModifierCallback() {
230
    private ClassPathModifier.Callback createClassPathModifierCallback() {
Lines 295-301 Link Here
295
        return helper;
298
        return helper;
296
    }
299
    }
297
300
298
    private Lookup createLookup(final AuxiliaryConfiguration aux, final J2SEProjectOperations ops) {
301
    private Lookup createLookup(final AuxiliaryConfiguration aux, final ProjectOperations.Callback opsCallback) {
299
        final FileEncodingQueryImplementation encodingQuery = QuerySupport.createFileEncodingQuery(evaluator(), ProjectProperties.SOURCE_ENCODING);
302
        final FileEncodingQueryImplementation encodingQuery = QuerySupport.createFileEncodingQuery(evaluator(), ProjectProperties.SOURCE_ENCODING);
300
        final Lookup base = Lookups.fixed(
303
        final Lookup base = Lookups.fixed(
301
            J2SEProject.this,
304
            J2SEProject.this,
Lines 351-357 Link Here
351
            ProjectClassPathModifier.extenderForModifier(cpMod),
354
            ProjectClassPathModifier.extenderForModifier(cpMod),
352
            buildExtender,
355
            buildExtender,
353
            cpMod,
356
            cpMod,
354
            ops,
357
            ProjectOperations.createBuilder(this, eval, updateHelper, refHelper, sourceRoots, testRoots).
358
                    addDataFiles("manifest.mf","master-application.jnlp","master-applet.jnlp","master-component.jnlp","preview-application.html","preview-applet.html").    //NOI18N
359
                    addMetadataFiles("xml-resources","catalog.xml").    //NOI18N
360
                    addPreservedPrivateProperties(ProjectProperties.APPLICATION_ARGS, ProjectProperties.RUN_WORK_DIR, ProjectProperties.COMPILE_ON_SAVE).
361
                    addUpdatedNameProperty(ProjectProperties.DIST_JAR, "$'{'dist.dir'}'/{0}.jar", true).    //NOI18N
362
                    addUpdatedNameProperty(J2SEProjectProperties.APPLICATION_TITLE, "{0}", false).  //NOI18N
363
                    setCallback(opsCallback).
364
                    build(),
355
            ProjectConfigurations.createConfigurationProviderBuilder(this, eval, updateHelper).
365
            ProjectConfigurations.createConfigurationProviderBuilder(this, eval, updateHelper).
356
                    addConfigurationsAffectActions(ActionProvider.COMMAND_RUN, ActionProvider.COMMAND_DEBUG).
366
                    addConfigurationsAffectActions(ActionProvider.COMMAND_RUN, ActionProvider.COMMAND_DEBUG).
357
                    setCustomizerAction(newConfigCustomizerAction()).
367
                    setCustomizerAction(newConfigCustomizerAction()).
Lines 963-966 Link Here
963
            }
973
            }
964
        };
974
        };
965
    }
975
    }
976
977
    @NonNull
978
    private static ProjectOperations.Callback newProjectOperationsCallback (
979
        @NonNull final J2SEProject project,
980
        @NonNull final UpdateProjectImpl projectUpdate) {
981
        return new ProjectOperations.Callback() {
982
            @Override
983
            public void beforeOperation(@NonNull final ProjectOperations.Callback.Operation operation) {
984
            }
985
            @Override
986
            @SuppressWarnings("fallthrough")
987
            public void afterOperation(
988
                    @NonNull final ProjectOperations.Callback.Operation operation,
989
                    @NullAllowed final String newName,
990
                    @NullAllowed final Pair<File, Project> oldProject) {
991
                switch (operation) {
992
                    case COPY:
993
                        projectUpdate.setTransparentUpdate(true);
994
                    case MOVE:
995
                    case RENAME:
996
                        project.setName(newName);
997
                }
998
            }
999
        };
1000
    }
966
}
1001
}
(-)a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProjectOperations.java (-435 lines)
Lines 1-435 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * Contributor(s):
28
 *
29
 * The Original Software is NetBeans. The Initial Developer of the Original
30
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
31
 * Microsystems, Inc. All Rights Reserved.
32
 *
33
 * If you wish your version of this file to be governed by only the CDDL
34
 * or only the GPL Version 2, indicate your decision by adding
35
 * "[Contributor] elects to include this software in this distribution
36
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
37
 * single choice of license, a recipient has the option to distribute
38
 * your version of this file under either the CDDL, the GPL Version 2 or
39
 * to extend the choice of license to its licensees as provided above.
40
 * However, if you add GPL Version 2 code and therefore, elected the GPL
41
 * Version 2 license, then the option applies only if the new code is
42
 * made subject to such option by the copyright holder.
43
 */
44
45
package org.netbeans.modules.java.j2seproject;
46
47
import java.io.File;
48
import java.io.IOException;
49
import java.util.ArrayList;
50
import java.util.Arrays;
51
import java.util.HashMap;
52
import java.util.List;
53
import java.util.Map;
54
import java.util.Properties;
55
import java.util.logging.Level;
56
import java.util.logging.Logger;
57
import org.apache.tools.ant.module.api.support.ActionUtils;
58
import org.netbeans.api.annotations.common.NonNull;
59
import org.netbeans.api.project.FileOwnerQuery;
60
import org.netbeans.api.project.Project;
61
import org.netbeans.api.project.ProjectInformation;
62
import org.netbeans.api.project.ProjectManager;
63
import org.netbeans.api.project.ProjectUtils;
64
import org.netbeans.modules.java.api.common.project.ProjectConfigurations;
65
import org.netbeans.modules.java.api.common.project.ProjectProperties;
66
import org.netbeans.modules.java.j2seproject.ui.customizer.J2SEProjectProperties;
67
import org.netbeans.spi.project.ActionProvider;
68
import org.netbeans.spi.project.CopyOperationImplementation;
69
import org.netbeans.spi.project.DeleteOperationImplementation;
70
import org.netbeans.spi.project.MoveOrRenameOperationImplementation;
71
import org.netbeans.spi.project.support.ant.AntProjectHelper;
72
import org.netbeans.spi.project.support.ant.EditableProperties;
73
import org.netbeans.spi.project.support.ant.PropertyUtils;
74
import org.openide.filesystems.FileObject;
75
import org.openide.filesystems.FileSystem;
76
import org.openide.filesystems.FileUtil;
77
import org.openide.util.Exceptions;
78
import org.openide.util.Lookup;
79
import org.openide.util.NbBundle;
80
import org.openide.util.Parameters;
81
import org.openide.util.Utilities;
82
83
/**
84
 *
85
 * @author Jan Lahoda
86
 */
87
public class J2SEProjectOperations implements DeleteOperationImplementation, CopyOperationImplementation, MoveOrRenameOperationImplementation {
88
    
89
    private static final Logger LOG = Logger.getLogger(J2SEProjectOperations.class.getName());
90
    
91
    private final J2SEProject project;
92
93
    private final UpdateProjectImpl updateProject;
94
    
95
    //RELY: Valid only on original project after the notifyMoving or notifyCopying was called
96
    private final Map<String,String> privatePropsToRestore = new HashMap<String,String>();
97
    //RELY: Valid only on original project after the notifyMoving or notifyCopying was called
98
    private String libraryPath;
99
    //RELY: Valid only on original project after the notifyMoving or notifyCopying was called
100
    private File libraryFile;
101
    //RELY: Valid only on original project after the notifyMoving or notifyCopying was called
102
    private boolean libraryWithinProject;
103
    //RELY: Valid only on original project after the notifyMoving or notifyCopying was called
104
    private String absolutesRelPath;
105
    //RELY: Valid only on original project after the notifyMoving or notifyCopying was called
106
    private FileSystem configs;
107
    
108
    public J2SEProjectOperations(
109
            @NonNull final J2SEProject project,
110
            @NonNull final UpdateProjectImpl updateProject) {
111
        Parameters.notNull("project", project); //NOI18N
112
        Parameters.notNull("updateProject", updateProject); //NOI18N
113
        this.project = project;
114
        this.updateProject = updateProject;
115
    }
116
    
117
    private static void addFile(FileObject projectDirectory, String fileName, List<FileObject> result) {
118
        FileObject file = projectDirectory.getFileObject(fileName);
119
        
120
        if (file != null) {
121
            result.add(file);
122
        }
123
    }
124
    
125
    public List<FileObject> getMetadataFiles() {
126
        FileObject projectDirectory = project.getProjectDirectory();
127
        List<FileObject> files = new ArrayList<FileObject>();
128
        
129
        addFile(projectDirectory, "nbproject", files); // NOI18N
130
        addFile(projectDirectory, J2SEProjectUtil.getBuildXmlName(project), files); // NOI18N
131
        addFile(projectDirectory, "xml-resources", files); //NOI18N
132
        addFile(projectDirectory, "catalog.xml", files); //NOI18N
133
        
134
        return files;
135
    }
136
    
137
    public List<FileObject> getDataFiles() {
138
        List<FileObject> files = new ArrayList<FileObject>();
139
        files.addAll(Arrays.asList(project.getSourceRoots().getRoots()));
140
        files.addAll(Arrays.asList(project.getTestSourceRoots().getRoots()));
141
        addFile(project.getProjectDirectory(), "manifest.mf", files); // NOI18N
142
        addFile(project.getProjectDirectory(), "master-application.jnlp", files); // NOI18N
143
        addFile(project.getProjectDirectory(), "master-applet.jnlp", files); // NOI18N
144
        addFile(project.getProjectDirectory(), "master-component.jnlp", files); // NOI18N
145
        addFile(project.getProjectDirectory(), "preview-application.html", files); // NOI18N
146
        addFile(project.getProjectDirectory(), "preview-applet.html", files); // NOI18N
147
        // add libraries folder if it is within project:
148
        AntProjectHelper helper = project.getAntProjectHelper();
149
        if (helper.getLibrariesLocation() != null) {
150
            File f = helper.resolveFile(helper.getLibrariesLocation());
151
            if (f != null && f.exists()) {
152
                FileObject libFolder = FileUtil.toFileObject(f).getParent();
153
                if (FileUtil.isParentOf(project.getProjectDirectory(), libFolder)) {
154
                    files.add(libFolder);
155
                }
156
            }
157
        }
158
        return files;
159
    }
160
    
161
    public @Override void notifyDeleting() throws IOException {
162
        clean();
163
    }
164
165
    private void clean() throws IOException {
166
        Properties p = new Properties();
167
        final AntTargetsProvider ap = project.getLookup().lookup(AntTargetsProvider.class);
168
        assert ap != null;
169
        String[] targetNames = ap.getTargetNames(ActionProvider.COMMAND_CLEAN, Lookup.EMPTY, p, false);
170
        assert targetNames != null;
171
        assert targetNames.length > 0;
172
        
173
        final FileObject buildXML = J2SEProjectUtil.getBuildXml(project);
174
        if (buildXML != null) {
175
            ActionUtils.runTarget(buildXML, targetNames, p).waitFinished();
176
        } else {
177
            LOG.log(
178
                Level.INFO,
179
                "Not cleaning the project: {0}, the build file: {1} does not exist.", //NOI18N
180
                new Object[] {
181
                    ProjectUtils.getInformation(project).getDisplayName(),
182
                    J2SEProjectUtil.getBuildXmlName(project)
183
                });
184
        }
185
    }
186
    
187
    public void notifyDeleted() throws IOException {
188
        project.getAntProjectHelper().notifyDeleted();
189
    }
190
    
191
    public void notifyCopying() {
192
        rememberLibraryLocation();
193
        readPrivateProperties();
194
        rememberConfigurations();
195
    }
196
    
197
    public void notifyCopied(Project original, File originalPath, String nueName) {
198
        if (original == null) {
199
            //do nothing for the original project.
200
            return ;
201
        }
202
        J2SEProjectOperations origOperations = original.getLookup().lookup(J2SEProjectOperations.class);
203
        fixLibraryLocation(origOperations);
204
        fixPrivateProperties(origOperations);
205
        fixDistJarProperty (nueName);
206
        fixApplicationTitle(nueName);
207
        project.getReferenceHelper().fixReferences(originalPath);
208
        //In case of copying project, the copy should be updated to a new version without notifying user.
209
        updateProject.setTransparentUpdate(true);
210
        project.setName(nueName);
211
        restoreConfigurations(origOperations);
212
    }
213
    
214
    public void notifyMoving() throws IOException {
215
        if (!this.project.getUpdateHelper().requestUpdate()) {
216
            throw new IOException (NbBundle.getMessage(J2SEProjectOperations.class,
217
                "MSG_OldProjectMetadata"));
218
        }
219
        rememberLibraryLocation();
220
        readPrivateProperties ();
221
        rememberConfigurations();
222
        clean();
223
    }
224
            
225
    public void notifyMoved(Project original, File originalPath, String nueName) {        
226
        if (original == null) {
227
            project.getAntProjectHelper().notifyDeleted();
228
            return ;
229
        }                
230
        J2SEProjectOperations origOperations = original.getLookup().lookup(J2SEProjectOperations.class);
231
        fixLibraryLocation(origOperations);
232
        fixPrivateProperties (origOperations);
233
        fixDistJarProperty (nueName);
234
        fixApplicationTitle(nueName);
235
        project.setName(nueName);        
236
	project.getReferenceHelper().fixReferences(originalPath);
237
        restoreConfigurations(origOperations);
238
    }
239
240
    public @Override void notifyRenaming() throws IOException {
241
        if (!this.project.getUpdateHelper().requestUpdate()) {
242
            throw new IOException(NbBundle.getMessage(J2SEProjectOperations.class, "MSG_OldProjectMetadata"));
243
        }
244
        clean();
245
    }
246
247
    public @Override void notifyRenamed(String nueName) throws IOException {
248
        fixDistJarProperty(nueName);
249
        fixApplicationTitle(nueName);
250
        project.setName(nueName);
251
    }
252
253
    private void fixLibraryLocation(J2SEProjectOperations original) throws IllegalArgumentException {
254
        String libPath = original.libraryPath;
255
        if (libPath != null) {
256
            if (!new File(libPath).isAbsolute()) {
257
                //relative path to libraries
258
                if (!original.libraryWithinProject) {
259
                    File file = original.libraryFile;
260
                    if (file == null) {
261
                        // could happen in some rare cases, but in that case the original project was already broken, don't fix.
262
                        return;
263
                    }
264
                    String relativized = PropertyUtils.relativizeFile(FileUtil.toFile(project.getProjectDirectory()), file);
265
                    if (relativized != null) {
266
                        project.getAntProjectHelper().setLibrariesLocation(relativized);
267
                    } else {
268
                        //cannot relativize, use absolute path
269
                        project.getAntProjectHelper().setLibrariesLocation(file.getAbsolutePath());
270
                    }
271
                } else {
272
                    //got copied over to new location.. the relative path is the same..
273
                }
274
            } else {
275
276
                //absolute path to libraries..
277
                if (original.libraryWithinProject) {
278
                    if (original.absolutesRelPath != null) {
279
                        project.getAntProjectHelper().setLibrariesLocation(PropertyUtils.resolveFile(FileUtil.toFile(project.getProjectDirectory()), original.absolutesRelPath).getAbsolutePath());
280
                    }
281
                } else {
282
                    // absolute path to an external folder stays the same.
283
                }
284
            }
285
        }
286
    }
287
    
288
    private void readPrivateProperties () {
289
        ProjectManager.mutex().readAccess(new Runnable() {
290
            public void run () {
291
                privatePropsToRestore.clear();
292
                backUpPrivateProp(ProjectProperties.APPLICATION_ARGS);
293
                backUpPrivateProp(ProjectProperties.RUN_WORK_DIR);
294
                backUpPrivateProp(ProjectProperties.COMPILE_ON_SAVE);                                                
295
            }
296
        });
297
    }    
298
    //where
299
    /**
300
     * Threading: Has to be called under project mutex
301
     */
302
    private void backUpPrivateProp(String propName) {
303
        assert ProjectManager.mutex().isReadAccess() || ProjectManager.mutex().isWriteAccess();
304
        final String tmp = project.getUpdateHelper().getProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH).getProperty(propName);
305
        if (tmp != null) {
306
            privatePropsToRestore.put(propName, tmp);
307
        }
308
    }
309
310
311
    
312
    private void fixPrivateProperties (final J2SEProjectOperations original) {
313
        if (original != null && !original.privatePropsToRestore.isEmpty()) {
314
            ProjectManager.mutex().writeAccess(new Runnable () {
315
                public void run () {
316
                    final EditableProperties ep = project.getUpdateHelper().getProperties (AntProjectHelper.PRIVATE_PROPERTIES_PATH);
317
                    for (Map.Entry<String,String> entry : original.privatePropsToRestore.entrySet()) {
318
                        ep.put(entry.getKey(), entry.getValue());
319
                    }
320
                    project.getUpdateHelper().putProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH, ep);
321
                }
322
            });
323
        }
324
    }
325
    
326
    private void fixDistJarProperty (final String newName) {
327
        ProjectManager.mutex().writeAccess(new Runnable () {
328
            public void run () {
329
                ProjectInformation pi = project.getLookup().lookup(ProjectInformation.class);
330
                String oldDistJar = pi == null ? null : "${dist.dir}/"+PropertyUtils.getUsablePropertyName(pi.getDisplayName())+".jar"; //NOI18N
331
                EditableProperties ep = project.getUpdateHelper().getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH);
332
                String propValue = ep.getProperty("dist.jar");  //NOI18N
333
                if (oldDistJar != null && oldDistJar.equals (propValue)) {
334
                    ep.put ("dist.jar","${dist.dir}/"+PropertyUtils.getUsablePropertyName(newName)+".jar"); //NOI18N
335
                    project.getUpdateHelper().putProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH,ep);
336
                }
337
            }
338
        });
339
    }
340
341
    private void fixApplicationTitle(final String newName) {
342
        ProjectManager.mutex().writeAccess(new Runnable () {
343
            public void run () {
344
                String oldName = ProjectUtils.getInformation(project).getDisplayName();
345
                EditableProperties ep = project.getUpdateHelper().getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH);
346
                String propValue = ep.getProperty(J2SEProjectProperties.APPLICATION_TITLE);  //NOI18N
347
                if (oldName != null && oldName.equals (propValue)) {
348
                    ep.put (J2SEProjectProperties.APPLICATION_TITLE,newName); //NOI18N
349
                    project.getUpdateHelper().putProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH,ep);
350
                }
351
            }
352
        });
353
    }
354
355
    private void rememberLibraryLocation() {
356
        libraryWithinProject = false;
357
        absolutesRelPath = null;
358
        libraryPath = project.getAntProjectHelper().getLibrariesLocation();
359
        if (libraryPath != null) {
360
            File prjRoot = FileUtil.toFile(project.getProjectDirectory());
361
            libraryFile = PropertyUtils.resolveFile(prjRoot, libraryPath);
362
            if (FileOwnerQuery.getOwner(Utilities.toURI(libraryFile)) == project &&
363
                    libraryFile.getAbsolutePath().startsWith(prjRoot.getAbsolutePath())) {
364
                //do not update the relative path if within the project..
365
                libraryWithinProject = true;
366
                FileObject fo = FileUtil.toFileObject(libraryFile);
367
                if (new File(libraryPath).isAbsolute() && fo != null) {
368
                    // if absolte path within project, it will get moved/copied..
369
                    absolutesRelPath = FileUtil.getRelativePath(project.getProjectDirectory(), fo);
370
                }
371
            }
372
        }
373
    }
374
    
375
    private void rememberConfigurations () {
376
        FileObject fo = project.getProjectDirectory().getFileObject(ProjectConfigurations.CONFIG_PROPS_PATH);
377
        if (fo != null) {
378
            //Has configurations
379
            try {
380
                FileSystem fs = FileUtil.createMemoryFileSystem();
381
                FileUtil.copyFile(fo, fs.getRoot(),fo.getName());
382
                fo = project.getProjectDirectory().getFileObject("nbproject/private/configs");      //NOI18N
383
                if (fo != null && fo.isFolder()) {
384
                    FileObject cfgs = fs.getRoot().createFolder("configs");                         //NOI18N
385
                    for (FileObject child : fo.getChildren()) {
386
                        FileUtil.copyFile(child, cfgs, child.getName());
387
                    }
388
                }
389
                configs = fs;
390
            } catch (IOException ioe) {
391
                Exceptions.printStackTrace(ioe);
392
            }
393
        }
394
    }
395
    
396
    private void restoreConfigurations (final J2SEProjectOperations original) {
397
        final FileSystem fs = original.configs;
398
        original.configs = null;
399
        if (fs != null) {
400
            try {
401
                FileObject fo = fs.getRoot().getFileObject("config.properties");        //NOI18N
402
                if (fo != null) {
403
                    FileObject privateFolder = FileUtil.createFolder(project.getProjectDirectory(), "nbproject/private");  //NOI18N
404
                    if (privateFolder != null) {
405
                        // #131857: SyncFailedException : check for file existence before FileUtil.copyFile
406
                        FileObject oldFile = privateFolder.getFileObject(fo.getName(), fo.getExt());
407
                        if (oldFile != null) {
408
                            //Probably delete outside of IDE + move. First try to repair FS cache
409
                            privateFolder.refresh();
410
                            oldFile = privateFolder.getFileObject(fo.getName(), fo.getExt());
411
                            if (oldFile != null) {
412
                                //The file still exists, delete it.
413
                                oldFile.delete();
414
                            }
415
                        }
416
417
                        FileUtil.copyFile(fo, privateFolder, fo.getName());
418
                    }                
419
                }
420
                fo = fs.getRoot().getFileObject("configs");                             //NOI18N
421
                if (fo != null) {
422
                    FileObject configsFolder = FileUtil.createFolder(project.getProjectDirectory(), "nbproject/private/configs");  //NOI18N
423
                    if (configsFolder != null) {
424
                        for (FileObject child : fo.getChildren()) {
425
                            FileUtil.copyFile(child, configsFolder, child.getName());
426
                        }
427
                    }
428
                }
429
            } catch (IOException ioe) {
430
                Exceptions.printStackTrace(ioe);
431
            }
432
        }
433
    }
434
435
}

Return to bug 237757