Source code: javax/ide/model/java/source/write/TreeManager.java
1 /*
2 * @(#)TreeManager.java
3 */
4
5 package javax.ide.model.java.source.write;
6
7 import java.net.URI;
8 import javax.ide.model.java.source.tree.FileT;
9
10 /**
11 * The TreeManager serves as a FileT factory. Clients obtain FileTs by
12 * requesting a FileT from the manager and by creating empty FileTs
13 * through the manager. Clients change the writability of FileTs by
14 * opening and closing TreeTransactions. For the sake of transaction
15 * consistency, a FileT belongs to exactly one TreeManager for the
16 * lifetime of the FileT. <p/>
17 *
18 * The TreeManager owns a single lockable resource (which may be itself)
19 * which must, at the minumum, provide the functionality of a read-write
20 * lock. Each FileT is tied to a single lockable resource (which may be
21 * itself) which is defined by the owning IDE and which must NOT coincide
22 * with the TreeManager's lock. This is usually an IDE lock controlling
23 * the writable of the underlying resource, e.g. {@link java.io.File}.
24 * Because the FileT's lock is not defined by the owning IDE and not the
25 * owning TreeManager, it is the responsibility (or neglect) of the owning
26 * IDE to safeguard against deadlocks and starvation. <p/>
27 *
28 * Attempting to make any change to a FileT marked as read-only will
29 * result in an IllegalStateException. Attempting to mark a FileT as
30 * writable when the FileT's underlying resource is not writable may
31 * result in a RuntimeException, at the discretion of the owning IDE.
32 * Although a FileT is logically writable only on the thread that made
33 * it writable, this manager does not enforce that policy. <p/>
34 *
35 * To start a multi-tree transaction, call
36 * <code>beginMultiTransaction</code> on this manager. To start a
37 * single-tree transaction, call <code>beginTransaction</code> on the
38 * FileT in question. <p/>
39 *
40 * Opening a new transaction that conflicts with an already open
41 * transaction results in a TreeTransactionException. This TreeManager
42 * does not provide blocking operations on its transaction state.
43 * Attempting to close a transaction on a thread different than than
44 * the opening thread results in a TreeTransactionException. A nested
45 * transaction is not considered to be at conflict with its enclosing
46 * transaction. Please see the section on nested transactions further
47 * below for more detail. <p/>
48 *
49 * TODO: If we were to provide such blocking operations, what would they
50 * look like? <p/>
51 *
52 *
53 * <h3> Write on commit </h3>
54 *
55 * The change to the underlying source file is not made until the
56 * owning transaction is committed. Transactions collect changes made
57 * to a FileT and then write them out to disk on commit. The only
58 * exception to this is anonymous FileTs, which have no underlying
59 * file. This is done to ensure that IDE listeners fire at the right
60 * time. Thus, a FileT change is not considered to be "done" by the
61 * IDE until its owning transaction has been committed. <p/>
62 *
63 *
64 * <h3> Transaction states </h3>
65 *
66 * A TreeManager can be in one of three states: read-only, single-tree
67 * transactions open, multi-tree transaction open. These states map
68 * directly to the state of a single read-write lock: read-only,
69 * locked shared, locked exclusive. The scope of a single-tree transaction
70 * is a single FileT. The scope of a multi-tree transaction is a
71 * TreeManager and all its owned FileTs. <p/>
72 *
73 * In a read-only state, no changes are allowed. All owned FileTs are
74 * marked as read-only. Opening a single-tree transaction on a FileT
75 * belonging to this manager moves this manager into a single-tree
76 * transactions open state. Opening a multi-tree transaction on this
77 * manager moves this manager into a multi-tree transaction open state.
78 * <p/>
79 *
80 * In a single-tree transactions open state, multiple single-tree
81 * transactions may be open with at most one transaction open per FileT.
82 * In this state, an owned FileT is writable if and only if there is an
83 * open single-tree transaction on said FileT. When all open transactions
84 * are closed on FileTs belonging to this manager, this manager moves into
85 * a read-only state. <p/>
86 *
87 * In a multi-tree transaction open state, there is a single open
88 * multi-tree transaction. Any change to a FileT belonging to this manager
89 * automatically marks it as writable. When the open transaction is closed,
90 * this manager moves into a read-only state. <p/>
91 *
92 * TODO: Should we provide the ability to upgrade from a single-tree
93 * transactions open state to a multi-tree transaction open state? Clearly,
94 * such an ability requires the ability of the manager's underlying lock
95 * to upgrade from a locked shared to a locked exclusive state. <p/>
96 *
97 *
98 * <h3> Nested transactions </h3>
99 *
100 * A single-tree transaction is nested if and only if, on open, there
101 * was already an open single-tree transaction on the target FileT or
102 * there was already an open multi-tree transaction on the owning
103 * manager. A multi-tree transaction is nested if and only if, on open,
104 * there was already on open multi-tree transaction on the target
105 * manager. <p/>
106 *
107 * At this writing, nested transactions are not supported and result
108 * in a TreeTransactionException. They may be supported in a later
109 * release. <p/>
110 *
111 *
112 * @author Andy Yu
113 */
114 public interface TreeManager
115 {
116 // ----------------------------------------------------------------------
117
118 /**
119 * Fetches the FileT for the given Java source URI (*.java). The
120 * classes contained in teh file represented by the URI can be
121 * fetched from the source file. If the URI does not represent a
122 * valid Java source file, or if the URI points to a non-existing
123 * file, then null is returned. <p/>
124 *
125 * Newly fetched FileTs are marked read-only. Previously fetched
126 * FileTs retain their previous read-only/writable state.<p/>
127 *
128 * @param sourceURI The target URI.
129 *
130 * @return The FileT representing the compilation unit at the
131 * specified URI.
132 */
133 public FileT getSourceFile(URI sourceURI);
134
135 /**
136 * Creates a new FileT for the given Java source URI (*.java). This
137 * will create a new empty file for the given URI, and return the
138 * FileT instance for it. If the file already exists on disk, then
139 * this will return null. <p/>
140 *
141 * FileTs may only be created when the TreeManager is in a
142 * multi-tree transaction open state. Hence, the FileT becomes
143 * writable once touched. <p/>
144 *
145 * @param sourceURI The target URI.
146 *
147 * @return The FileT for the newly created compilation unit at the
148 * specified URI, null if the file was not created.
149 *
150 * @throws IOException if the new file cannot be created.
151 *
152 * @throws IllegalArgumentException if the URI is not recognized as
153 * a Java source file.
154 *
155 * @throws TreeTransactionException if this manager is not in
156 * the multi-tree transaction open state.
157 */
158 public FileT createSourceFile(URI sourceURI);
159
160 /**
161 * Fetches an anonymous file. <p/>
162 *
163 * An anonymous file is not attached to any URI or lockable
164 * resource, can not be referenced outside, is always writable, and
165 * does not participate in transaction mechanics. In particular, an
166 * anonymous file can not have open transactions, is not affected by
167 * the owning manager's transaction state, and does not affect the
168 * owning manager's transaction state. All TreeResolver operations
169 * may be validly performed on the anonymous file as on any other
170 * file. <p/>
171 *
172 * This is useful for debugging features who may need to parse
173 * anonymous expressions. <p/>
174 *
175 * Must always return a different non-null FileT each time. <p/>
176 *
177 * @return A FileT for an anonymous file.
178 */
179 public FileT getAnonymousFile();
180
181 /**
182 * Clears the destination FileT (unlinks all its children), clones
183 * the source FileT contents, and links the cloned Trees into the
184 * destination FileT. No transactions are opened in the process.
185 * The source FileT may be an anoymous file and may even belong to a
186 * different TreeManager. <p/>
187 *
188 * If the destination FileT cannot be written to, an exception will
189 * be thrown. <p/>
190 *
191 * @param source The source FileT.
192 * @param destination The destination FileT.
193 */
194 public void cloneSourceFile(FileT source, FileT destination);
195
196 /**
197 * Places this FileFactory in an exclusive open transaction state.
198 * Begins a multi-tree transaction. End the transaction with either
199 * {@link MultiTreeTransaction#abort()} or
200 * {@link MultiTreeTransaction#commit()}. <p/>
201 *
202 * @return The transaction object for the newly begun multi-tree
203 * transaction.
204 */
205 public MultiTreeTransaction beginMultiTransaction();
206
207 /**
208 * Returns the in-progress multi-tree transaction, null if none.
209 *
210 * @return The in-progress transaction object, null if none.
211 */
212 public MultiTreeTransaction getMultiTransaction();
213 }