2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
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]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
28
* Microsystems, Inc. All Rights Reserved.
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.
42
package org.netbeans.modules.java.j2seproject;
44
import java.beans.PropertyChangeEvent;
45
import java.beans.PropertyChangeListener;
46
import java.io.IOException;
47
import java.util.Collection;
48
import javax.lang.model.element.TypeElement;
49
import javax.swing.SwingUtilities;
50
import org.netbeans.api.java.classpath.ClassPath;
51
import org.netbeans.api.java.source.Task;
52
import org.netbeans.api.java.source.ClasspathInfo;
53
import org.netbeans.api.java.source.CompilationController;
54
import org.netbeans.api.java.source.CompilationController;
55
import org.netbeans.api.java.source.ElementHandle;
56
import org.netbeans.api.java.source.JavaSource;
57
import org.netbeans.api.java.source.SourceUtils;
58
import org.netbeans.api.project.Project;
59
import org.netbeans.api.project.ProjectManager;
60
import org.netbeans.spi.project.support.ant.AntProjectHelper;
61
import org.netbeans.spi.project.support.ant.EditableProperties;
62
import org.netbeans.spi.project.support.ant.PropertyEvaluator;
63
import org.openide.filesystems.FileChangeAdapter;
64
import org.openide.filesystems.FileObject;
65
import org.openide.filesystems.FileRenameEvent;
66
import org.openide.util.Exceptions;
67
import org.openide.util.Mutex;
68
import org.openide.util.MutexException;
69
import org.openide.util.RequestProcessor;
73
* @author Tomas Zezula
75
public class MainClassUpdater extends FileChangeAdapter implements PropertyChangeListener {
77
private static final RequestProcessor RP = new RequestProcessor ("main-class-updater",1); //NOI18N
79
private final Project project;
80
private final PropertyEvaluator eval;
81
private final UpdateHelper helper;
82
private final ClassPath sourcePath;
83
private final String mainClassPropName;
84
private FileObject current;
86
/** Creates a new instance of MainClassUpdater */
87
public MainClassUpdater(final Project project, final PropertyEvaluator eval,
88
final UpdateHelper helper, final ClassPath sourcePath, final String mainClassPropName) {
89
assert project != null;
91
assert helper != null;
92
assert sourcePath != null;
93
assert mainClassPropName != null;
94
this.project = project;
97
this.sourcePath = sourcePath;
98
this.mainClassPropName = mainClassPropName;
99
this.eval.addPropertyChangeListener(this);
100
this.addFileChangeListener ();
103
public synchronized void unregister () {
104
if (current != null) {
105
current.removeFileChangeListener(this);
109
public void propertyChange(PropertyChangeEvent evt) {
110
if (this.mainClassPropName.equals(evt.getPropertyName())) {
111
//Go out of the ProjectManager.MUTEX, see #118722
112
RP.post(new Runnable () {
114
MainClassUpdater.this.addFileChangeListener ();
121
public void fileRenamed (final FileRenameEvent evt) {
122
final FileObject _current;
123
synchronized (this) {
124
_current = this.current;
126
if (evt.getFile() == _current) {
127
Runnable r = new Runnable () {
130
final String oldMainClass = ProjectManager.mutex().readAccess(new Mutex.ExceptionAction<String>() {
131
public String run() throws Exception {
132
return eval.getProperty(mainClassPropName);
136
Collection<ElementHandle<TypeElement>> main = SourceUtils.getMainClasses(_current);
137
String newMainClass = null;
138
if (!main.isEmpty()) {
139
ElementHandle<TypeElement> mainHandle = main.iterator().next();
140
newMainClass = mainHandle.getQualifiedName();
142
if (newMainClass != null && !newMainClass.equals(oldMainClass) && helper.requestSave() &&
143
// XXX ##84806: ideally should update nbproject/configs/*.properties in this case:
144
eval.getProperty(J2SEConfigurationProvider.PROP_CONFIG) == null) {
145
final String newMainClassFinal = newMainClass;
146
ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction<Void>() {
147
public Void run() throws Exception {
148
EditableProperties props = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
149
props.put (mainClassPropName, newMainClassFinal);
150
helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, props);
151
ProjectManager.getDefault().saveProject (project);
156
} catch (IOException e) {
157
Exceptions.printStackTrace(e);
159
catch (MutexException e) {
160
Exceptions.printStackTrace(e);
164
if (SwingUtilities.isEventDispatchThread()) {
168
SwingUtilities.invokeLater(r);
173
private void addFileChangeListener () {
174
synchronized (MainClassUpdater.this) {
175
if (current != null) {
176
current.removeFileChangeListener(MainClassUpdater.this);
180
final String mainClassName = org.netbeans.modules.java.j2seproject.MainClassUpdater.this.eval.getProperty(mainClassPropName);
181
if (mainClassName != null) {
183
FileObject[] roots = sourcePath.getRoots();
184
if (roots.length>0) {
185
ClassPath bootCp = ClassPath.getClassPath(roots[0], ClassPath.BOOT);
186
ClassPath compileCp = ClassPath.getClassPath(roots[0], ClassPath.COMPILE);
187
final ClasspathInfo cpInfo = ClasspathInfo.create(bootCp, compileCp, sourcePath);
188
JavaSource js = JavaSource.create(cpInfo);
189
js.runWhenScanFinished(new Task<CompilationController>() {
191
public void run(CompilationController c) throws Exception {
192
TypeElement te = c.getElements().getTypeElement(mainClassName);
194
synchronized (MainClassUpdater.this) {
195
current = SourceUtils.getFile(te, cpInfo);
196
if (current != null && sourcePath.contains(current)) {
197
current.addFileChangeListener(MainClassUpdater.this);
205
} catch (IOException ioe) {