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.openide.loaders;
043:
044: import java.io.IOException;
045: import java.util.*;
046: import java.util.logging.Level;
047:
048: import org.openide.*;
049: import org.openide.filesystems.*;
050:
051: /** Loader for any kind of <code>MultiDataObject</code>. It provides
052: * support for recognition of a composite data object and registering
053: * entries into it.
054: *
055: * @author Jaroslav Tulach
056: */
057: public abstract class MultiFileLoader extends DataLoader {
058: private static final long serialVersionUID = 1521919955690157343L;
059:
060: /** Creates new multi file loader.
061: * @param representationClass the representation class
062: * @deprecated Use MultiFileLoader#MultiFileLoader(String) instead.
063: */
064: @Deprecated
065: protected MultiFileLoader(
066: Class<? extends DataObject> representationClass) {
067: super (representationClass);
068: }
069:
070: /** Creates new multi file loader.
071: * @param representationClassName the fully qualified name of the
072: * representation class.
073: *
074: * @since 1.10
075: */
076: protected MultiFileLoader(String representationClassName) {
077: super (representationClassName);
078: }
079:
080: /* Provides standard implementation for recognizing files in the
081: * loader. First of all the findEntry method is called to allow the
082: * subclass to find right entry for the
083: *
084: * @param fo file object to recognize
085: * @param recognized recognized files buffer.
086: * @exception DataObjectExistsException if the data object for specific
087: * primary file already exists (thrown by constructor of DataObject)
088: * @exception IOException if the object is recognized but cannot be created
089: *
090: * @return suitable data object or <CODE>null</CODE> if the handler cannot
091: * recognize this object (or its group)
092: */
093: protected final DataObject handleFindDataObject(FileObject fo,
094: RecognizedFiles recognized) throws IOException {
095: // finds primary file for given file
096: FileObject primary = findPrimaryFileImpl(fo);
097:
098: // if this loader does not recognizes this file => return
099: if (primary == null)
100: return null;
101:
102: boolean willLog = ERR.isLoggable(Level.FINE);
103:
104: if (willLog) {
105: ERR.fine(getClass().getName() + " is accepting: " + fo); // NOI18N
106: }
107:
108: if (primary != fo) {
109: if (willLog) {
110: ERR
111: .fine("checking correctness: primary is different than provided file: "
112: + primary + " fo: " + fo); // NOI18N
113: }
114: Enumeration en = DataLoaderPool.getDefault().allLoaders();
115: for (;;) {
116: DataLoader l = (DataLoader) en.nextElement();
117: if (l == this ) {
118: ERR.fine("ok, consistent"); // NOI18N
119: break;
120: }
121: if (l instanceof MultiFileLoader) {
122: MultiFileLoader ml = (MultiFileLoader) l;
123: if (ml.findPrimaryFile(primary) == primary) {
124: if (willLog) {
125: ERR
126: .fine("loader seems to also take care of the file: "
127: + ml);
128: }
129: DataObject snd;
130: try {
131: snd = ml
132: .findDataObject(primary, recognized);
133: } catch (DataObjectExistsException ex) {
134: snd = ex.getDataObject();
135: }
136: if (snd != null) {
137: return null;
138: }
139: }
140: }
141: }
142: }
143:
144: MultiDataObject obj;
145: try {
146: // create the multi object
147: obj = createMultiObject(primary);
148: if (willLog) {
149: ERR.fine(getClass().getName() + " created object for: "
150: + fo + " obj: " + obj); // NOI18N
151: }
152: } catch (DataObjectExistsException ex) {
153: // object already exists
154: DataObject dataObject = ex.getDataObject();
155: if (willLog) {
156: ERR.fine(getClass().getName()
157: + " object already exists for: " + fo
158: + " obj: " + dataObject); // NOI18N
159: }
160:
161: if (dataObject.getLoader() != this ) {
162: if (willLog) {
163: ERR.fine(getClass().getName()
164: + " loader is wrong: "
165: + dataObject.getLoader().getClass()
166: .getName()); // NOI18N
167: }
168:
169: if (dataObject.getLoader() instanceof MultiFileLoader) {
170: MultiFileLoader mfl = (MultiFileLoader) dataObject
171: .getLoader();
172: FileObject loaderPrimary = mfl
173: .findPrimaryFileImpl(fo);
174: ERR.log(Level.FINE, "Its primary file is {0}",
175: loaderPrimary); // NOI18N
176: if (loaderPrimary != null
177: && dataObject.getPrimaryFile() != loaderPrimary) {
178: ERR
179: .log(
180: Level.FINE,
181: "Which is different than primary of found: {0}",
182: dataObject); // NOI18N
183:
184: Enumeration before = DataLoaderPool
185: .getDefault().allLoaders();
186: while (before.hasMoreElements()) {
187: Object o = before.nextElement();
188: if (o == mfl) {
189: ERR.log(Level.FINE, "Returning null"); // NOI18N
190: return null;
191: }
192: if (o == this ) {
193: ERR.log(Level.FINE, "The loader" + mfl
194: + " is after " + this
195: + ". So do break."); // NOI18N
196: break;
197: }
198: }
199: }
200: }
201:
202: // try to update the data object by allowing other
203: // loaders to take care of the object
204: dataObject = checkCollision(dataObject, fo);
205: }
206:
207: if (!(dataObject instanceof MultiDataObject)) {
208: // but if it is not MultiDataObject, propadate the exception
209: if (willLog) {
210: ERR.fine(getClass().getName()
211: + " object is not MultiDataObject: "
212: + dataObject); // NOI18N
213: }
214: throw ex;
215: }
216: obj = (MultiDataObject) dataObject;
217: } catch (IOException ex) {
218: ERR.log(Level.FINE, null, ex);
219: throw ex;
220: }
221:
222: if (obj.getLoader() != this ) {
223: if (willLog) {
224: ERR.fine(getClass().getName() + " wrong loader: "
225: + obj.getLoader().getClass().getName()); // NOI18N
226: }
227: // this primary file is recognized by a different
228: // loader. We should not add entries to it
229: return obj;
230: }
231:
232: // mark all secondary entries used
233: if (willLog) {
234: ERR.fine(getClass().getName()
235: + " marking secondary entries"); // NOI18N
236: }
237: obj.markSecondaryEntriesRecognized(recognized);
238:
239: // if the file is not between
240: if (willLog) {
241: ERR.fine(getClass().getName() + " register entry: " + fo); // NOI18N
242: }
243: org.openide.loaders.MultiDataObject.Entry e = obj
244: .registerEntry(fo);
245: if (willLog) {
246: ERR.fine(getClass().getName() + " success: " + e); // NOI18N
247: }
248:
249: return obj;
250: }
251:
252: /** For a given file finds the primary file.
253: * @param fo the (secondary) file
254: *
255: * @return the primary file for the file or <code>null</code> if the file is not
256: * recognized by this loader
257: */
258: protected abstract FileObject findPrimaryFile(FileObject fo);
259:
260: /** Creates the right data object for a given primary file.
261: * It is guaranteed that the provided file will actually be the primary file
262: * returned by {@link #findPrimaryFile}.
263: *
264: * @param primaryFile the primary file
265: * @return the data object for this file
266: * @exception DataObjectExistsException if the primary file already has a data object
267: */
268: protected abstract MultiDataObject createMultiObject(
269: FileObject primaryFile) throws DataObjectExistsException,
270: IOException;
271:
272: /** Creates the right primary entry for a given primary file.
273: *
274: * @param obj requesting object
275: * @param primaryFile primary file recognized by this loader
276: * @return primary entry for that file
277: */
278: protected abstract MultiDataObject.Entry createPrimaryEntry(
279: MultiDataObject obj, FileObject primaryFile);
280:
281: /** Creates a new secondary entry for a given file.
282: * Note that separate entries must be created for every secondary
283: * file within a given multi-file data object.
284: *
285: * @param obj requesting object
286: * @param secondaryFile a secondary file
287: * @return the entry
288: */
289: protected abstract MultiDataObject.Entry createSecondaryEntry(
290: MultiDataObject obj, FileObject secondaryFile);
291:
292: /** Called when there is a collision between a data object that
293: * this loader tries to create and already existing one.
294: *
295: * @param obj existing data object
296: * @param file the original file that has been recognized by this loader
297: * as bellonging to obj data object
298: * @return the data object created for this or null
299: */
300: DataObject checkCollision(DataObject obj, FileObject file) {
301: /* JST: Make protected when necessary. Do not forget to
302: * change UniFileDataLoader too.
303: */
304: FileObject primary = obj.getPrimaryFile();
305:
306: /*Set refusing = */DataObjectPool.getPOOL()
307: .revalidate(
308: new HashSet<FileObject>(Collections
309: .singleton(primary)));
310: // ok, the obj is discarded
311: DataObject result = DataObjectPool.getPOOL().find(primary);
312: return result;
313: }
314:
315: /** Called when an entry of the data object is deleted.
316: *
317: * @param obj the object to check
318: */
319: void checkConsistency(MultiDataObject obj) {
320: /* JST: Make protected when necessary. Do not forget to
321: * change UniFileDataLoader too.
322: */
323: FileObject primary = obj.getPrimaryFile();
324: if (primary.equals(findPrimaryFileImpl(primary))) {
325: // ok recognized
326: return;
327: }
328:
329: // something is wrong the loader does not recognize the data
330: // object anymore
331: try {
332: obj.setValid(false);
333: } catch (java.beans.PropertyVetoException ex) {
334: // ignore
335: }
336: }
337:
338: /** Called before list of files belonging to a data object
339: * is returned from MultiDataObject.files () method. This allows
340: * each loader to perform additional tests and update the set of
341: * entries for given data object.
342: * <P>
343: * Current implementation scans all files in directory.
344: *
345: * @param obj the object to test
346: */
347: void checkFiles(MultiDataObject obj) {
348: /* JST: Make protected (and rename) when necessary. Do not forget to
349: * change UniFileDataLoader too.
350: */
351:
352: FileObject primary = obj.getPrimaryFile();
353: assert primary != null : "Object " + obj
354: + " cannot have null primary file"; // NOI18N
355: FileObject parent = primary.getParent();
356: assert parent != null : "Object " + obj
357: + " cannot have null parent file"; // NOI18N
358:
359: FileObject[] arr = parent.getChildren();
360: for (int i = 0; i < arr.length; i++) {
361: FileObject pf = findPrimaryFileImpl(arr[i]);
362:
363: if (pf == primary) {
364: // this object could belong to this loader
365: try {
366: // this will go thru regular process of looking for
367: // data object and register this file with the right (but not
368: // necessary this one) data object
369: DataObject.find(arr[i]);
370: } catch (DataObjectNotFoundException ex) {
371: // ignore
372: }
373: }
374: }
375: }
376:
377: MultiDataObject.Entry createSecondaryEntryImpl(MultiDataObject obj,
378: FileObject secondaryFile) {
379: return createSecondaryEntry(obj, secondaryFile);
380: }
381:
382: FileObject findPrimaryFileImpl(FileObject fo) {
383: return findPrimaryFile(fo);
384: }
385: }
|