Lines 1-245
Link Here
|
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.ant.freeform; |
43 |
|
44 |
import java.io.IOException; |
45 |
import java.net.MalformedURLException; |
46 |
import java.net.URL; |
47 |
import java.util.Iterator; |
48 |
import java.util.Set; |
49 |
import java.util.TreeSet; |
50 |
import javax.xml.parsers.SAXParser; |
51 |
import javax.xml.parsers.SAXParserFactory; |
52 |
import org.netbeans.modules.ant.freeform.spi.ProjectNature; |
53 |
import org.openide.ErrorManager; |
54 |
import org.openide.cookies.EditorCookie; |
55 |
import org.openide.filesystems.FileAttributeEvent; |
56 |
import org.openide.filesystems.FileChangeListener; |
57 |
import org.openide.filesystems.FileEvent; |
58 |
import org.openide.filesystems.FileObject; |
59 |
import org.openide.filesystems.FileRenameEvent; |
60 |
import org.openide.filesystems.FileUtil; |
61 |
import org.openide.filesystems.URLMapper; |
62 |
import org.openide.loaders.DataObject; |
63 |
import org.openide.loaders.DataObjectNotFoundException; |
64 |
import org.openide.text.Line; |
65 |
import org.openide.util.Lookup; |
66 |
import org.openide.util.NbBundle; |
67 |
import org.openide.windows.IOProvider; |
68 |
import org.openide.windows.InputOutput; |
69 |
import org.openide.windows.OutputEvent; |
70 |
import org.openide.windows.OutputListener; |
71 |
import org.xml.sax.SAXException; |
72 |
import org.xml.sax.SAXNotRecognizedException; |
73 |
import org.xml.sax.SAXParseException; |
74 |
import org.xml.sax.helpers.DefaultHandler; |
75 |
|
76 |
/** |
77 |
* Checks validity of freeform project.xml files. |
78 |
* @see "#47288" |
79 |
* @author Jesse Glick |
80 |
*/ |
81 |
final class ProjectXmlValidator extends DefaultHandler implements FileChangeListener { |
82 |
|
83 |
private final FileObject projectXml; |
84 |
private InputOutput io; |
85 |
|
86 |
public ProjectXmlValidator(FileObject projectXml) { |
87 |
this.projectXml = projectXml; |
88 |
projectXml.addFileChangeListener(this); |
89 |
validateProjectXml(); |
90 |
} |
91 |
|
92 |
private void validateProjectXml() { |
93 |
if (System.getProperty("netbeans.user") == null) { // NOI18N |
94 |
// Probably in a unit test; skip it. |
95 |
return; |
96 |
} |
97 |
open(); |
98 |
try { |
99 |
// XXX may want to preinitialize the desired SAXParserFactory and keep it statically, for speed |
100 |
SAXParserFactory f = SAXParserFactory.newInstance(); |
101 |
f.setNamespaceAware(true); |
102 |
f.setValidating(true); |
103 |
SAXParser p = f.newSAXParser(); |
104 |
p.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", // NOI18N |
105 |
"http://www.w3.org/2001/XMLSchema"); // NOI18N |
106 |
p.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource", getSchemas()); // NOI18N |
107 |
p.parse(projectXml.getURL().toString(), this); |
108 |
} catch (SAXParseException e) { |
109 |
log(e); |
110 |
} catch (Exception e) { |
111 |
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); |
112 |
} finally { |
113 |
close(); |
114 |
} |
115 |
} |
116 |
|
117 |
/** |
118 |
* Compute a list of XML schema locations to be used for validating project.xml files. |
119 |
*/ |
120 |
private static String[] getSchemas() { |
121 |
Set<String> schemas = new TreeSet<String>(); |
122 |
// XXX should not refer to schema in another module; wait for #42686 to solve properly |
123 |
schemas.add("nbres:/org/netbeans/modules/project/ant/project.xsd"); // NOI18N |
124 |
schemas.add("nbres:/org/netbeans/modules/ant/freeform/resources/freeform-project-general.xsd"); // NOI18N |
125 |
schemas.add("nbres:/org/netbeans/modules/ant/freeform/resources/freeform-project-general-2.xsd"); // NOI18N |
126 |
for (ProjectNature nature : FreeformProject.PROJECT_NATURES.allInstances()) { |
127 |
schemas.addAll(nature.getSchemas()); |
128 |
} |
129 |
return schemas.toArray(new String[schemas.size()]); |
130 |
} |
131 |
|
132 |
public void fileChanged(FileEvent fe) { |
133 |
validateProjectXml(); |
134 |
} |
135 |
|
136 |
public void fileRenamed(FileRenameEvent fe) {} |
137 |
|
138 |
public void fileAttributeChanged(FileAttributeEvent fe) {} |
139 |
|
140 |
public void fileFolderCreated(FileEvent fe) {} |
141 |
|
142 |
public void fileDeleted(FileEvent fe) {} |
143 |
|
144 |
public void fileDataCreated(FileEvent fe) {} |
145 |
|
146 |
public void warning(SAXParseException e) throws SAXException { |
147 |
log(e); |
148 |
} |
149 |
|
150 |
public void error(SAXParseException e) throws SAXException { |
151 |
log(e); |
152 |
} |
153 |
|
154 |
public void fatalError(SAXParseException e) throws SAXException { |
155 |
throw e; |
156 |
} |
157 |
|
158 |
/** Close any old error tab. */ |
159 |
private void open() { |
160 |
if (io != null) { |
161 |
io.closeInputOutput(); |
162 |
io = null; |
163 |
} |
164 |
} |
165 |
|
166 |
/** Log a parse error, opening error tab as needed. */ |
167 |
private void log(SAXParseException e) { |
168 |
if (io == null) { |
169 |
String title = NbBundle.getMessage(ProjectXmlValidator.class, "LBL_project.xml_errors", FileUtil.getFileDisplayName(projectXml)); |
170 |
io = IOProvider.getDefault().getIO(title, true); |
171 |
io.select(); |
172 |
} |
173 |
try { |
174 |
io.getErr().println(e.getLocalizedMessage(), new Hyperlink(e.getSystemId(), e.getLineNumber(), e.getColumnNumber())); |
175 |
} catch (IOException x) { |
176 |
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, x); |
177 |
} |
178 |
} |
179 |
|
180 |
/** Close the stream for the error tab, if one is open, but leave it visible. */ |
181 |
private void close() { |
182 |
if (io != null) { |
183 |
io.getErr().close(); |
184 |
io.getOut().close(); // XXX why is this necessary? |
185 |
} |
186 |
} |
187 |
|
188 |
private static final class Hyperlink implements OutputListener { |
189 |
|
190 |
private final String uri; |
191 |
private final int line, column; |
192 |
|
193 |
public Hyperlink(String uri, int line, int column) { |
194 |
this.uri = uri; |
195 |
this.line = line; |
196 |
this.column = column; |
197 |
} |
198 |
|
199 |
public void outputLineAction(OutputEvent ev) { |
200 |
FileObject fo; |
201 |
try { |
202 |
fo = URLMapper.findFileObject(new URL(uri)); |
203 |
} catch (MalformedURLException e) { |
204 |
assert false : e; |
205 |
return; |
206 |
} |
207 |
if (fo == null) { |
208 |
return; |
209 |
} |
210 |
DataObject d; |
211 |
try { |
212 |
d = DataObject.find(fo); |
213 |
} catch (DataObjectNotFoundException e) { |
214 |
assert false : e; |
215 |
return; |
216 |
} |
217 |
EditorCookie ec = d.getCookie(EditorCookie.class); |
218 |
if (ec == null) { |
219 |
return; |
220 |
} |
221 |
if (line != -1) { |
222 |
try { |
223 |
// XXX do we need to call ec.openDocument as in org.apache.tools.ant.module.run.Hyperlink? |
224 |
Line l = ec.getLineSet().getOriginal(line - 1); |
225 |
if (column != -1) { |
226 |
l.show(Line.SHOW_GOTO, column - 1); |
227 |
} else { |
228 |
l.show(Line.SHOW_GOTO); |
229 |
} |
230 |
} catch (IndexOutOfBoundsException e) { |
231 |
// forget it |
232 |
ec.open(); |
233 |
} |
234 |
} else { |
235 |
ec.open(); |
236 |
} |
237 |
} |
238 |
|
239 |
public void outputLineSelected(OutputEvent ev) {} |
240 |
|
241 |
public void outputLineCleared(OutputEvent ev) {} |
242 |
|
243 |
} |
244 |
|
245 |
} |