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-2007 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: package org.netbeans.modules.visualweb.insync;
042:
043: import org.netbeans.api.project.Project;
044: import org.openide.filesystems.FileObject;
045:
046: import org.netbeans.modules.visualweb.project.jsf.api.JsfProjectUtils;
047:
048: //NB60 import org.netbeans.modules.visualweb.insync.faces.refactoring.MdrInSyncSynchronizer;
049:
050: /**
051: * General Model abstraction. A Model is a wrapper for one or more Units and serves to bootstrap the
052: * units and coordinate them with Project and its Items.
053: *
054: * @author cquinn
055: */
056: public abstract class Model implements SourceUnitListener {
057:
058: public static final Model[] EMPTY_ARRAY = {};
059:
060: // EAT! TODO
061: // We need to do some work on straightening out this circular sync issue, but
062: // not time now :(
063: public static final boolean CHECK_CIRCULAR_SYNC = false;
064:
065: // For debugging, capturing who is doing the sync
066: protected Exception syncInProgress;
067:
068: /**
069: * Manager tracking source unit updates for this model and coordinating undo/redo operations.
070: */
071: protected UndoManager undoManager = new UndoManager();
072:
073: /**
074: */
075: public interface Factory {
076:
077: /**
078: * Possibly create an instance of the associated model iff it would be appropriate for the
079: * given file object.
080: *
081: * @param set Owning ModelSet
082: * @param file FileObject to create Model for
083: * @return The new Model or null if N/A
084: */
085: public Model newInstance(ModelSet set, FileObject file);
086: }
087:
088: protected static Model getInstance(FileObject file,
089: Class modelSetType, boolean forceCreate) {
090: ModelSet models = ModelSet.getInstance(file, modelSetType);
091: if (models != null)
092: return models.getModel(file);
093: return null;
094: }
095:
096: protected static Model getModel(FileObject file) {
097: ModelSet modelSet = ModelSet.getModelSet(file);
098: if (modelSet != null) {
099: return modelSet.getModel(file);
100: }
101: return null;
102: }
103:
104: //--------------------------------------------------------------------------------- Construction
105:
106: /** NB and Project coordination */
107: protected ModelSet owner;
108: protected FileObject file;
109:
110: /**
111: * Construct a new model under a given owner and for a given NB file
112: *
113: * @param owner
114: * @param file
115: */
116: protected Model(ModelSet owner, FileObject file) {
117: assert file != null;
118: this .owner = owner;
119: this .file = file;
120: }
121:
122: /**
123: * Destroy this model causing it to clean up all its references. Called when the project is
124: * closing, or the underlying file is deleted. Models must never be used after destroy is
125: * called.
126: */
127: public void destroy() {
128: owner = null;
129: file = null;
130: }
131:
132: /**
133: * ONLY called when my parent is being destroy'ed, in order to make sure there are no contexts
134: * active while client views are updating during event notification of models being destroyed.
135: *
136: */
137: public void resetOwner() {
138: owner = null;
139: }
140:
141: //------------------------------------------------------------------------------------ Accessors
142:
143: /**
144: * Get the owning ModelSet for this Model.
145: * @return the owning ModelSet for this Model.
146: */
147: public ModelSet getOwner() {
148: return owner;
149: }
150:
151: public abstract ParserAnnotation[] getErrors();
152:
153: /**
154: * Get the primary FileObject that this Model is abstracting.
155: *
156: * @return the primary FileObject that this Model is abstracting
157: */
158: public FileObject getFile() {
159: return file;
160: }
161:
162: /**
163: * Get the undo manager associated with this model.
164: *
165: * @return the undo manager associated with this model
166: */
167: public UndoManager getUndoManager() {
168: return undoManager;
169: }
170:
171: //----------------------------------------------------------------- Project & DataObject Helpers
172:
173: public Project getProject() {
174: if (owner == null)
175: return null;
176: return owner.getProject();
177: }
178:
179: /**
180: * Get the folder within the owning Project that holds the web source files.
181: *
182: * @return the web source folder.
183: */
184: public FileObject getWebFolder() {
185: return JsfProjectUtils.getDocumentRoot(getProject());
186: }
187:
188: /**
189: * Lock the entire model for write access.
190: * @param description The human readable description of the operation to be performed during
191: * lock.
192: * @return The undo event object that will be populated with state needed to undo what is done
193: * during the lock.
194: */
195: public abstract UndoEvent writeLock(String description);
196:
197: /**
198: * Unlock a previously locked model. Unlock should <b>always </b> be called exactly once after
199: * lock, and so should be placed in a finally block.
200: *
201: * @param event The undo event object that was returned from writeLock().
202: */
203: public abstract void writeUnlock(UndoEvent event);
204:
205: /**
206: * @return
207: */
208: public abstract boolean isWriteLocked();
209:
210: protected void beginMdrTransation() {
211: }
212:
213: protected void endMdrTransaction() {
214: }
215:
216: /**
217: * Cause the model to synchronize its state with the underlying source buffers as needed. Will
218: * do nothing if the model is already in a sync'd state.
219: */
220: public void sync() {
221: syncImpl();
222: }
223:
224: protected abstract void syncImpl();
225:
226: public void fireModelChanged() {
227: getOwner().fireModelChanged(this );
228: }
229:
230: public abstract void saveUnits();
231:
232: /**
233: * Cause the model to flush any model changes down to the underlying souce buffers as needed.
234: * Will do nothing if the source buffers are already up to date.
235: *
236: * @see writeLock,writeUnlock for the prefered way to commit changes to source.
237: */
238: public void flush() {
239: flushImpl();
240: }
241:
242: public abstract void flushImpl();
243:
244: /**
245: * Should only be used if you are certain this will not cause a problem.
246: * At moment this is only used by refactoring mechanism.
247: * See the caller in ModelSet.plannedChange for more information.
248: *
249: */
250: public void flushNonJavaUnits() {
251: flushNonJavaUnitsImpl();
252: }
253:
254: public abstract void flushNonJavaUnitsImpl();
255:
256: /**
257: * Called when a file in the project is renamed by the user. Model implementations should handle
258: * this by updating all internal references.
259: *
260: * @param oldName The old name of the renamed file.
261: * @param newName The new name of the renamed file.
262: * @param ext The file extension which can be used to determine the type of file.
263: * @param file The actual NB file object.
264: * @param remove Indicates if the model needs to be removed
265: */
266: public void fileRenamed(String oldName, String newName, String ext,
267: FileObject file, boolean remove) {
268: }
269:
270: /**
271: * Provide for an easier string to be displayed when this object is seen in an object inspector.
272: */
273: public String toString() {
274: StringBuffer buffer = new StringBuffer();
275: buffer.append("["); // NOI18N
276: toString(buffer);
277: buffer.append("]"); // NOI18N
278: return super .toString() + buffer.toString();
279: }
280:
281: /**
282: * Subclasses should override this to add extra information desired for the string to be displayed when this object is seen in an object inspector.
283: * @param buffer
284: */
285: public void toString(StringBuffer buffer) {
286: // buffer.append(getClass().getName().substring(getClass().getPackage().getName().length() + 1));
287: if (file == null)
288: buffer.append("null"); // NOI18N
289: else {
290: buffer.append(" file: ");
291: buffer.append(file.getNameExt());
292: }
293: }
294:
295: public void sourceUnitSaved(final SourceUnit unit) {
296: }
297:
298: public void sourceUnitModelDirtied(SourceUnit unit) {
299: //NB60 MdrInSyncSynchronizer.get().addModelDirtied(this);
300: }
301:
302: protected boolean needSyncing = true;
303:
304: public void sourceUnitSourceDirtied(SourceUnit unit) {
305: //NB60 MdrInSyncSynchronizer.get().addModelDirtied(this);
306: needSyncing = true;
307: getOwner().addToModelsToSync(this );
308: }
309:
310: /**
311: * Return true ONLY if I have an owner and all my file objects are valid.
312: * I had to add this in order to handle issues with threading, queue on different threads,
313: * during refactoring. We can run into a case where a file has been removed, but the
314: * model is still around. This is not a good situation, so now we check for isValid.
315: *
316: * @return
317: */
318: public boolean isValid() {
319: if (getOwner() == null)
320: return false;
321: return true;
322: }
323:
324: }
|