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-2006 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.j2ee.ddloaders.common.xmlutils;
44
import org.openide.cookies.*;
45
import org.openide.nodes.CookieSet;
46
import org.openide.filesystems.FileObject;
47
import org.openide.loaders.MultiFileLoader;
48
import org.openide.loaders.XMLDataObject;
49
import org.openide.text.Line;
50
import org.openide.windows.*;
51
import org.openide.util.NbBundle;
54
import java.util.logging.Level;
55
import java.util.logging.Logger;
57
import org.openide.xml.*;
58
import org.netbeans.api.xml.cookies.CheckXMLCookie;
59
import org.netbeans.spi.xml.cookies.*;
61
/** Represents a XMLJ2eeDataObject in the Repository.
65
public abstract class XMLJ2eeDataObject extends XMLDataObject implements CookieSet.Factory {
67
protected boolean nodeDirty = false;
68
private boolean documentDirty = true;
69
private boolean savingDocument;
70
private InputStream inputStream;
71
private InputOutput inOut;
72
protected XMLJ2eeEditorSupport editor;
73
private boolean documentValid=true;
74
private SAXParseError error;
75
private org.openide.text.Annotation errorAnnotation;
77
private static final long serialVersionUID = -515751072013886985L;
79
/** Property name for property documentValid */
80
public static final String PROP_DOC_VALID = "documentValid"; // NOI18N
82
public XMLJ2eeDataObject(FileObject pf, MultiFileLoader loader)
83
throws org.openide.loaders.DataObjectExistsException {
86
getCookieSet().add(XMLJ2eeEditorSupport.class, this);
87
getCookieSet().add(EditCookie.class, this);
88
getCookieSet().add(EditorCookie.class, this);
89
getCookieSet().add(LineCookie.class, this);
90
getCookieSet().add(PrintCookie.class, this);
91
getCookieSet().add(CloseCookie.class, this);
92
// added CheckXMLCookie
93
InputSource in = DataObjectAdapters.inputSource(this);
94
CheckXMLCookie checkCookie = new CheckXMLSupport(in);
95
getCookieSet().add(checkCookie);
97
// Issuezilla 23493 - this is the way how to disable the OpenCoookie from this data object
98
protected EditorCookie createEditorCookie () {
101
/** Update the node from document. This method is called after document is changed.
102
* @param is Input source for the document
103
* @return number of the line with error (document is invalid), 0 (xml document is valid)
105
protected abstract SAXParseError updateNode(org.xml.sax.InputSource is) throws java.io.IOException;
106
/** gets the Icon Base for node delegate when parser accepts the xml document as valid
107
* @return Icon Base for node delegate
109
protected abstract String getIconBaseForValidDocument();
111
/** gets the Icon Base for node delegate when parser finds error(s) in xml document
112
* @return Icon Base for node delegate
114
protected abstract String getIconBaseForInvalidDocument();
116
/** Implements <code>CookieSet.Factory</code> interface. */
117
public org.openide.nodes.Node.Cookie createCookie(Class clazz) {
118
if(clazz.isAssignableFrom(XMLJ2eeEditorSupport.class))
119
return getEditorSupport();
124
/** Gets editor support for this data object. */
125
protected synchronized XMLJ2eeEditorSupport getEditorSupport() {
127
editor = new XMLJ2eeEditorSupport(this);
131
/** gets the String for status line when parser finds error(s) in xml document
132
* @param error info about an error
133
* @return String for status line
135
public String getOutputStringForInvalidDocument(SAXParseError error){
136
//return error.getErrorText()+" ["+error.getErrorLine()+","+error.getErrorColumn()+"]";
137
String mes = NbBundle.getMessage (XMLJ2eeDataObject.class, "TXT_errorMessage",
138
new Object [] { error.getErrorText(),
139
new Integer(error.getErrorLine()),
140
new Integer(error.getErrorColumn()) });
143
/** Getter for property nodeDirty.
144
* @return Value of property nodeDirty.
146
public boolean isNodeDirty(){
150
/** setter for property documentDirty. Method updateDocument() usually setsDocumentDirty to false
152
public void setDocumentDirty(boolean dirty){
156
/** Getter for property documentDirty.
157
* @return Value of property documentDirty.
159
public boolean isDocumentDirty(){
160
return documentDirty;
163
/** Setter for property nodeDirty.
164
* @param dirty New value of property nodeDirty.
166
public void setNodeDirty(boolean dirty){
170
/** This method repairs Node Delegate (usually after changing document by property editor)
172
protected void repairNode(){
173
// PENDING: set the icon in Node
174
// ((DataNode)getNodeDelegate()).setIconBase (getIconBaseForValidDocument());
176
inOut.closeInputOutput();
177
errorAnnotation.detach();
181
/** This method parses XML document and calls abstract updateNode method which
182
* updates corresponding Node.
184
public void parsingDocument(){
185
//System.out.println("background parsing "); // NOI18N
186
//Thread.dumpStack();
187
SAXParseError err=null;
189
err=updateNode(prepareInputSource());
191
catch (Exception e) {
192
Logger.getLogger("global").log(Level.INFO, null, e);
193
setDocumentValid(false);
201
setDocumentValid(true);
203
setDocumentValid(false);
207
/** This method is used for obtaining the current source of xml document.
208
* First try if document is in the memory. If not, provide the input from
209
* underlayed file object.
210
* @return The input source from memory or from file
211
* @exception IOException if some problem occurs
213
protected org.xml.sax.InputSource prepareInputSource() throws java.io.IOException {
214
if ((editor != null) && (editor.isDocumentLoaded())) {
215
// loading from the memory (Document)
216
final javax.swing.text.Document doc = editor.getDocument();
217
final String[] str = new String[1];
218
// safely take the text from the document
219
Runnable run = new Runnable() {
222
str[0] = doc.getText(0, doc.getLength());
224
catch (javax.swing.text.BadLocationException e) {
231
// TODO: this StringReader should be also closed.
232
StringReader reader = new StringReader(str[0]);
233
return new org.xml.sax.InputSource(reader);
236
// loading from the file
237
inputStream = new BufferedInputStream(getPrimaryFile().getInputStream());
238
return new org.xml.sax.InputSource(inputStream);
242
/** This method has to be called everytime after prepareInputSource calling.
243
* It is used for closing the stream, because it is not possible to access the
244
* underlayed stream hidden in InputSource.
245
* It is save to call this method without opening.
247
protected void closeInputSource() {
248
InputStream is = inputStream;
253
catch (IOException e) {
254
// nothing to do, if exception occurs during saving.
256
if (is == inputStream) {
261
public boolean isDocumentValid(){
262
return documentValid;
264
public void setDocumentValid (boolean valid){
265
if (documentValid!=valid) {
269
firePropertyChange (PROP_DOC_VALID, !documentValid ? Boolean.TRUE : Boolean.FALSE, documentValid ? Boolean.TRUE : Boolean.FALSE);
272
public void addSaveCookie(SaveCookie cookie){
273
getCookieSet().add(cookie);
275
public void removeSaveCookie(){
276
org.openide.nodes.Node.Cookie cookie = getCookie(SaveCookie.class);
277
if (cookie!=null) getCookieSet().remove(cookie);
280
public void setSavingDocument(boolean saving){
281
savingDocument=saving;
283
public boolean isSavingDocument(){
284
return savingDocument;
286
public void displayErrorMessage() {
287
if (error==null) return;
288
if (errorAnnotation==null)
289
errorAnnotation = new org.openide.text.Annotation() {
290
public String getAnnotationType() {
291
return "xml-j2ee-annotation"; // NOI18N
293
String desc = NbBundle.getMessage(XMLJ2eeDataObject.class, "HINT_XMLErrorDescription");
294
public String getShortDescription() {
299
inOut=org.openide.windows.IOProvider.getDefault().getIO(NbBundle.getMessage(XMLJ2eeDataObject.class, "TXT_parser"), false);
300
inOut.setFocusTaken (false);
301
OutputWriter outputWriter = inOut.getOut();
302
int line = Math.max(0,error.getErrorLine());
303
// int column = Math.max(0,error.getErrorColumn());
305
LineCookie cookie = (LineCookie)getCookie(LineCookie.class);
306
// getting Line object
307
Line xline = cookie.getLineSet ().getCurrent(line==0?0:line-1);
308
// attaching Annotation
309
errorAnnotation.attach(xline);
312
outputWriter.reset();
313
// defining of new OutputListener
314
IOCtl outList= new IOCtl(xline);
315
outputWriter.println(this.getOutputStringForInvalidDocument(error),outList);
316
}catch(IOException e){}
319
public void setValid(boolean valid) throws java.beans.PropertyVetoException {
320
if (!valid && inOut!=null) inOut.closeInputOutput();
321
super.setValid(valid);
324
final class IOCtl implements OutputListener {
328
public IOCtl (Line xline) {
332
public void outputLineSelected (OutputEvent ev) {
333
errorAnnotation.attach(xline);
334
xline.show(Line.SHOW_TRY_SHOW);
337
public void outputLineAction (OutputEvent ev) {
338
errorAnnotation.attach(xline);
339
xline.show(Line.SHOW_TRY_SHOW);
342
public void outputLineCleared (OutputEvent ev) {
343
errorAnnotation.detach();
347
public static class J2eeErrorHandler implements ErrorHandler {
349
private XMLJ2eeDataObject xmlJ2eeDataObject;
351
public J2eeErrorHandler(XMLJ2eeDataObject obj) {
352
xmlJ2eeDataObject=obj;
355
public void error(SAXParseException exception) throws SAXException {
356
xmlJ2eeDataObject.createSAXParseError(exception);
360
public void fatalError(SAXParseException exception) throws SAXException {
361
xmlJ2eeDataObject.createSAXParseError(exception);
365
public void warning(SAXParseException exception) throws SAXException {
366
xmlJ2eeDataObject.createSAXParseError(exception);
371
private void createSAXParseError(SAXParseException error){
372
this.error = new SAXParseError(error);