001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.web.jsf;
043:
044: import java.io.IOException;
045: import java.io.InputStream;
046: import java.util.logging.Level;
047: import java.util.logging.Logger;
048: import org.netbeans.modules.web.jsf.api.facesmodel.FacesConfig;
049: import org.openide.filesystems.FileObject;
050: import org.openide.loaders.DataObjectExistsException;
051: import org.openide.loaders.MultiDataObject;
052: import org.openide.nodes.CookieSet;
053: import org.openide.nodes.Node;
054: import org.openide.util.Lookup;
055: import org.w3c.dom.Document;
056: import org.xml.sax.*;
057: import org.netbeans.api.xml.cookies.ValidateXMLCookie;
058: import org.netbeans.api.xml.cookies.CheckXMLCookie;
059: import org.netbeans.modules.xml.api.XmlFileEncodingQueryImpl;
060: import org.netbeans.spi.queries.FileEncodingQueryImplementation;
061: import org.netbeans.spi.xml.cookies.*;
062:
063: /**
064: *
065: * @author Petr Pisl
066: */
067: public class JSFConfigDataObject extends MultiDataObject implements
068: org.openide.nodes.CookieSet.Factory {
069:
070: private static JSFCatalog jsfCatalog = new JSFCatalog();
071: private boolean documentDirty = true;
072: private boolean documentValid = true;
073: protected boolean nodeDirty = false;
074: private InputStream inputStream;
075: /** Editor support for text data object. */
076: private transient JSFConfigEditorSupport editorSupport;
077: private SAXParseError error;
078: private FacesConfig lastGoodFacesConfig = null;
079:
080: /** Property name for property documentValid */
081: public static final String PROP_DOC_VALID = "documentValid"; // NOI18N
082:
083: /** Creates a new instance of StrutsConfigDataObject */
084: public JSFConfigDataObject(FileObject pf, JSFConfigLoader loader)
085: throws DataObjectExistsException {
086: super (pf, loader);
087: init();
088:
089: }
090:
091: private void init() {
092: CookieSet cookies = getCookieSet();
093:
094: getCookieSet().add(JSFConfigEditorSupport.class, this );
095:
096: // Creates Check XML and Validate XML context actions
097: InputSource in = DataObjectAdapters.inputSource(this );
098: CheckXMLCookie checkCookie = new CheckXMLSupport(in);
099: getCookieSet().add(checkCookie);
100: ValidateXMLCookie validateCookie = new ValidateXMLSupport(in);
101: getCookieSet().add(validateCookie);
102: getCookieSet().assign(FileEncodingQueryImplementation.class,
103: XmlFileEncodingQueryImpl.singleton());
104: }
105:
106: /**
107: * Provides node that should represent this data object. When a node for
108: * representation in a parent is requested by a call to getNode (parent)
109: * it is the exact copy of this node
110: * with only parent changed. This implementation creates instance
111: * <CODE>DataNode</CODE>.
112: * <P>
113: * This method is called only once.
114: *
115: * @return the node representation for this data object
116: * @see DataNode
117: */
118: protected synchronized Node createNodeDelegate() {
119: return new JSFConfigNode(this );
120: }
121:
122: /** Implements <code>CookieSet.Factory</code> interface. */
123: public Node.Cookie createCookie(Class clazz) {
124: if (clazz.isAssignableFrom(JSFConfigEditorSupport.class))
125: return getEditorSupport();
126: else
127: return null;
128: }
129:
130: /** Gets editor support for this data object. */
131: public JSFConfigEditorSupport getEditorSupport() {
132: if (editorSupport == null) {
133: synchronized (this ) {
134: if (editorSupport == null)
135: editorSupport = new JSFConfigEditorSupport(this );
136: }
137: }
138:
139: return editorSupport;
140: }
141:
142: public FacesConfig getFacesConfig() throws java.io.IOException {
143: if (lastGoodFacesConfig == null)
144: parsingDocument();
145: return lastGoodFacesConfig;
146: }
147:
148: /** This method is used for obtaining the current source of xml document.
149: * First try if document is in the memory. If not, provide the input from
150: * underlayed file object.
151: * @return The input source from memory or from file
152: * @exception IOException if some problem occurs
153: */
154: protected InputStream prepareInputSource()
155: throws java.io.IOException {
156: if ((getEditorSupport() != null)
157: && (getEditorSupport().isDocumentLoaded())) {
158: // loading from the memory (Document)
159: return getEditorSupport().getInputStream();
160: } else {
161: return getPrimaryFile().getInputStream();
162: }
163: }
164:
165: /** This method has to be called everytime after prepareInputSource calling.
166: * It is used for closing the stream, because it is not possible to access the
167: * underlayed stream hidden in InputSource.
168: * It is save to call this method without opening.
169: */
170: protected void closeInputSource() {
171: InputStream is = inputStream;
172: if (is != null) {
173: try {
174: is.close();
175: } catch (IOException e) {
176: // nothing to do, if exception occurs during saving.
177: }
178: if (is == inputStream) {
179: inputStream = null;
180: }
181: }
182: }
183:
184: /** This method parses XML document and calls updateNode method which
185: * updates corresponding Node.
186: */
187: public void parsingDocument() {
188: error = null;
189: try {
190: error = updateNode(prepareInputSource());
191: } catch (Exception e) {
192: Logger.getLogger("global").log(Level.INFO, null, e);
193: setDocumentValid(false);
194: return;
195: } finally {
196: closeInputSource();
197: documentDirty = false;
198: }
199: if (error == null) {
200: setDocumentValid(true);
201: } else {
202: setDocumentValid(false);
203: }
204: setNodeDirty(false);
205: }
206:
207: public void setDocumentValid(boolean valid) {
208: if (documentValid != valid) {
209: if (valid)
210: repairNode();
211: documentValid = valid;
212: firePropertyChange(PROP_DOC_VALID,
213: !documentValid ? Boolean.TRUE : Boolean.FALSE,
214: documentValid ? Boolean.TRUE : Boolean.FALSE);
215: }
216: }
217:
218: /** This method repairs Node Delegate (usually after changing document by property editor)
219: */
220: protected void repairNode() {
221: // PENDING: set the icon in Node
222: // ((DataNode)getNodeDelegate()).setIconBase (getIconBaseForValidDocument());
223: org.openide.awt.StatusDisplayer.getDefault().setStatusText(""); // NOI18N
224: /* if (inOut!=null) {
225: inOut.closeInputOutput();
226: errorAnnotation.detach();
227: }*/
228: }
229:
230: private org.w3c.dom.Document getDomDocument(InputStream inputSource)
231: throws SAXParseException {
232: try {
233: // creating w3c document
234: org.w3c.dom.Document doc = org.netbeans.modules.schema2beans.GraphManager
235: .createXmlDocument(new org.xml.sax.InputSource(
236: inputSource), false, jsfCatalog,
237: new J2eeErrorHandler(this ));
238: return doc;
239: } catch (Exception e) {
240: // XXX Change that
241: throw new SAXParseException(e.getMessage(),
242: new org.xml.sax.helpers.LocatorImpl());
243: }
244: }
245:
246: /** Update the node from document. This method is called after document is changed.
247: * @param is Input source for the document
248: * @return number of the line with error (document is invalid), 0 (xml document is valid)
249: */
250: // TODO is prepared for handling arrors, but not time to finish it.
251: protected SAXParseError updateNode(InputStream is)
252: throws java.io.IOException {
253: try {
254: Document doc = getDomDocument(is);
255:
256: //TODO new api
257: //JSF version = JSFCatalog.extractVersion(doc);
258: //check version, use impl class to create graph
259: //TODO new API
260: // if (FacesConfig.VERSION_1_1.equals(version)) {
261: // lastGoodFacesConfig = org.netbeans.modules.web.jsf.config.model_1_1.FacesConfig.createGraph(doc);
262: // }
263: // if (FacesConfig.VERSION_1_0.equals(version)) {
264: // lastGoodFacesConfig = org.netbeans.modules.web.jsf.config.model_1_1.FacesConfig.createGraph(doc);
265: // }
266: // if (FacesConfig.VERSION_1_2.equals(version)) {
267: // lastGoodFacesConfig = org.netbeans.modules.web.jsf.config.model_1_2.FacesConfig.createGraph(doc);
268: // }
269: } catch (SAXParseException ex) {
270: return new SAXParseError(ex);
271: } catch (SAXException ex) {
272: throw new IOException();
273: }
274: return null;
275: }
276:
277: public boolean isDocumentValid() {
278: return documentValid;
279: }
280:
281: /** setter for property documentDirty. Method updateDocument() usually setsDocumentDirty to false
282: */
283: public void setDocumentDirty(boolean dirty) {
284: documentDirty = dirty;
285: }
286:
287: /** Getter for property documentDirty.
288: * @return Value of property documentDirty.
289: */
290: public boolean isDocumentDirty() {
291: return documentDirty;
292: }
293:
294: /** Getter for property nodeDirty.
295: * @return Value of property nodeDirty.
296: */
297: public boolean isNodeDirty() {
298: return nodeDirty;
299: }
300:
301: /** Setter for property nodeDirty.
302: * @param dirty New value of property nodeDirty.
303: */
304: public void setNodeDirty(boolean dirty) {
305: nodeDirty = dirty;
306: }
307:
308: org.openide.nodes.CookieSet getCookieSet0() {
309: return getCookieSet();
310: }
311:
312: @Override
313: public Lookup getLookup() {
314: return getCookieSet().getLookup();
315: }
316:
317: public static class J2eeErrorHandler implements ErrorHandler {
318:
319: private JSFConfigDataObject dataObject;
320:
321: public J2eeErrorHandler(JSFConfigDataObject obj) {
322: dataObject = obj;
323: }
324:
325: public void error(SAXParseException exception)
326: throws SAXException {
327: dataObject.createSAXParseError(exception);
328: throw exception;
329: }
330:
331: public void fatalError(SAXParseException exception)
332: throws SAXException {
333: dataObject.createSAXParseError(exception);
334: throw exception;
335: }
336:
337: public void warning(SAXParseException exception)
338: throws SAXException {
339: dataObject.createSAXParseError(exception);
340: throw exception;
341: }
342: }
343:
344: private void createSAXParseError(SAXParseException error) {
345: this .error = new SAXParseError(error);
346: }
347:
348: }
|