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:
042: package org.netbeans.modules.cnd.modelimpl.cache.impl;
043:
044: import antlr.TokenStream;
045: import antlr.collections.AST;
046: import java.io.IOException;
047: import java.io.InputStream;
048: import java.util.logging.Level;
049: import org.netbeans.modules.cnd.api.model.CsmFile;
050: import org.netbeans.modules.cnd.api.model.CsmUID;
051: import org.netbeans.modules.cnd.apt.support.APTBuilder;
052: import org.netbeans.modules.cnd.apt.support.APTTokenStreamBuilder;
053: import org.netbeans.modules.cnd.apt.structure.APTFile;
054: import org.netbeans.modules.cnd.apt.support.APTPreprocHandler;
055: import org.netbeans.modules.cnd.apt.utils.APTUtils;
056: import org.netbeans.modules.cnd.modelimpl.cache.CacheManager;
057: import org.netbeans.modules.cnd.modelimpl.cache.FileCache;
058: import org.netbeans.modules.cnd.modelimpl.csm.core.FileImpl;
059: import org.netbeans.modules.cnd.modelimpl.debug.DiagnosticExceptoins;
060: import org.netbeans.modules.cnd.modelimpl.debug.TraceFlags;
061: import org.netbeans.modules.cnd.modelimpl.uid.UIDCsmConverter;
062:
063: /**
064: * synchronized bridge to cache file
065: * @author Vladimir Voskresensky
066: */
067: //final class FileCacheSyncBridge implements FileCache {
068: final class FileCacheSyncBridge {
069: // cache
070: private FileCacheWeakImpl storage;
071: // flags indicated which data exists in cache on disk
072: private boolean astMaybeOnDisk;
073: private boolean aptMaybeOnDisk;
074: private boolean aptLightMaybeOnDisk;
075:
076: private CsmUID<CsmFile> fileUID;
077:
078: private String absPath;
079:
080: // valid FALSE means we need to interrupt current activity
081: private boolean validCache = true;
082:
083: public FileCacheSyncBridge(FileImpl file) {
084: assert (file != null);
085: this .storage = new FileCacheWeakImpl();
086: if (file.getBuffer().isFileBased()) {
087: // we think, everything is on disk
088: astMaybeOnDisk = true;
089: aptMaybeOnDisk = true;
090: aptLightMaybeOnDisk = true;
091: } else {
092: astMaybeOnDisk = false;
093: aptMaybeOnDisk = false;
094: aptLightMaybeOnDisk = false;
095: }
096: _setFile(file);
097: initLocks(_getAbsolutePath());
098: }
099:
100: public APTFile findAPT() {
101: if (TraceFlags.TRACE_CACHE) {
102: System.err.println("CACHE: findAPT for "
103: + _getAbsolutePath());
104: }
105: APTFile apt = null;
106: synchronized (aptLock) {
107: apt = storage.getAPT();
108: if (apt == null && validCache) {
109: if (aptMaybeOnDisk) {
110: synchronized (loadLock) {
111: apt = storage.getAPT();
112: if (apt == null && validCache && aptMaybeOnDisk) {
113: if (TraceFlags.TRACE_CACHE) {
114: System.err
115: .println("CACHE: findAPT loading from disk for "
116: + _getAbsolutePath());
117: }
118: FileCache loaded = loadValidCache();
119: if (loaded != null) {
120: if (TraceFlags.TRACE_CACHE) {
121: System.err
122: .println("CACHE: findAPT loaded from disk for "
123: + _getAbsolutePath());
124: }
125: apt = loaded.getAPT();
126: }
127: }
128: }
129: if (apt == null) {
130: aptMaybeOnDisk = false;
131: }
132: }
133: if (apt == null) {
134: // need to create full APT
135: apt = createAPTFull();
136: }
137: }
138: // apt should be asked only once! Clear memory
139: storage.setAPT(null);
140: }
141: return apt;
142: }
143:
144: public APTFile findAPTLight() {
145: if (TraceFlags.TRACE_CACHE) {
146: System.err.println("CACHE: findAPTLight for "
147: + _getAbsolutePath());
148: }
149: APTFile aptLight = null;
150: synchronized (aptLightLock) {
151: aptLight = storage.getAPTLight();
152: if (aptLight == null && validCache) {
153: if (aptLightMaybeOnDisk) {
154: synchronized (loadLock) {
155: aptLight = storage.getAPTLight();
156: if (aptLight == null && validCache
157: && aptLightMaybeOnDisk) {
158: if (TraceFlags.TRACE_CACHE) {
159: System.err
160: .println("CACHE: findAPTLight loading from disk for "
161: + _getAbsolutePath());
162: }
163: FileCache loaded = loadValidCache();
164: if (loaded != null) {
165: if (TraceFlags.TRACE_CACHE) {
166: System.err
167: .println("CACHE: findAPTLight loaded from disk for "
168: + _getAbsolutePath());
169: }
170: aptLight = loaded.getAPTLight();
171: }
172: }
173: }
174: if (aptLight == null) {
175: aptLightMaybeOnDisk = false;
176: }
177: }
178: if (aptLight == null) {
179: // need to create APT light
180: aptLight = createAPTLight();
181: }
182: }
183: }
184: if (TraceFlags.TRACE_CACHE) {
185: if (aptLight == null) {
186: System.err
187: .println("CACHE: WARNING!!! No APT Light for "
188: + _getAbsolutePath());
189: }
190: }
191: return aptLight;
192: }
193:
194: public FileCache findCacheWithAST(APTPreprocHandler preprocHandler) {
195: if (TraceFlags.TRACE_CACHE) {
196: System.err.println("CACHE: findCacheWithAST for "
197: + _getAbsolutePath());
198: }
199: AST ast = null;
200: APTFile aptLight = null;
201: APTFile aptFull = null;
202: FileCache loaded = null;
203: synchronized (astLock) {
204: ast = storage.getAST(preprocHandler);
205: if (ast == null) {
206: if (TraceFlags.TRACE_CACHE) {
207: System.err
208: .println("CACHE: findCacheWithAST AST not in memory for "
209: + _getAbsolutePath());
210: }
211: if (validCache && astMaybeOnDisk) {
212: synchronized (loadLock) {
213: ast = storage.getAST(preprocHandler);
214: if (ast == null && validCache && astMaybeOnDisk) {
215: if (TraceFlags.TRACE_CACHE) {
216: System.err
217: .println("CACHE: findCacheWithAST loading AST for "
218: + _getAbsolutePath());
219: }
220: loaded = loadValidCache();
221: if (loaded != null) {
222: ast = loaded.getAST(preprocHandler);
223: if (TraceFlags.TRACE_CACHE) {
224: System.err
225: .println("CACHE: findCacheWithAST loaded AST from disk for "
226: + _getAbsolutePath());
227: }
228: }
229: }
230: }
231: } else {
232: if (TraceFlags.TRACE_CACHE) {
233: System.err
234: .println("CACHE: findCacheWithAST not necessary load cache, because AST not in it for "
235: + _getAbsolutePath());
236: }
237: }
238: if (loaded == null) {
239: aptFull = storage.getAPT();
240: if (aptFull == null) {
241: if (TraceFlags.TRACE_CACHE) {
242: System.err
243: .println("CACHE: findCacheWithAST (AST preparation) creating APT for "
244: + _getAbsolutePath());
245: }
246: aptFull = createAPT(true);
247: if (aptFull != null) {
248: aptLight = storage.getAPTLight();
249: assert (aptLight != null);
250: } else {
251: aptLight = null;
252: }
253: } else {
254: if (TraceFlags.TRACE_CACHE) {
255: System.err
256: .println("CACHE: findCacheWithAST (AST preparation) got APT from memory for "
257: + _getAbsolutePath());
258: }
259: aptLight = storage.getAPTLight();
260: }
261: }
262: } else {
263: aptLight = storage.getAPTLight();
264: }
265: // clear full APT and AST on requesting AST to save memory
266: if (TraceFlags.TRACE_CACHE) {
267: System.err
268: .println("CACHE: findCacheWithAST clear APT and AST after request to AST");
269: }
270: storage.setAPT(null);
271: storage.setAST(null, null);
272: astMaybeOnDisk = loaded == null ? ast != null : loaded
273: .getAST(null) != null;
274: }
275:
276: if (TraceFlags.TRACE_CACHE) {
277: if (aptLight == null && loaded == null) {
278: System.err
279: .println("CACHE: no APT light while getting AST for "
280: + _getAbsolutePath());
281: }
282: }
283: return loaded == null ? new FileCacheImpl(aptLight, aptFull,
284: ast) : loaded;
285: }
286:
287: void invalidate() {
288: validCache = false;
289: }
290:
291: // public APTFile getAPT() {
292: // return findAPT();
293: // }
294: //
295: // public APTFile getAPTLight() {
296: // return findAPTLight();
297: // }
298: //
299: // public AST getAST(APTPreprocHandler preprocHandler) {
300: // return findCacheWithAST(preprocHandler).getAST(preprocHandler);
301: // }
302:
303: public void updateStorage(FileCache cache) {
304: APTFile aptLight = cache.getAPTLight();
305: if (aptLight != null) {
306: this .storage.setAPTLight(aptLight);
307: aptLightMaybeOnDisk = true;
308: }
309: if (cache.getAPT() != null) {
310: // this.storage.setAPT(aptFull);
311: aptMaybeOnDisk = true;
312: }
313: if (cache.getAST(null) != null) {
314: // this.storage.setAST(ast,null);
315: astMaybeOnDisk = true;
316: }
317: }
318:
319: ////////////////////////////////////////////////////////////////////////////
320: // APT creating
321:
322: private APTFile createAPTFull() {
323: if (TraceFlags.TRACE_CACHE) {
324: System.err.println("CACHE: creating full APT for "
325: + _getAbsolutePath());
326: }
327: return createAPT(true);
328: }
329:
330: private APTFile createAPTLight() {
331: if (TraceFlags.TRACE_CACHE) {
332: System.err.println("CACHE: creating APT light for "
333: + _getAbsolutePath());
334: }
335: return createAPT(false);
336: }
337:
338: private Object createAPTLock = new Object() {
339: public String toString() {
340: return "APT creating lock for " + _getAbsolutePath(); // NOI18N
341: }
342: };
343:
344: private APTFile createAPT(boolean full) {
345: synchronized (createAPTLock) {
346: // quick exit: check if already was added by another creator
347: // during wait
348: APTFile out = full ? storage.getAPT() : storage
349: .getAPTLight();
350: if (out == null) {
351: String path = _getAbsolutePath();
352: // ok, create new apt
353: // build token stream for file
354: InputStream stream = null;
355: try {
356: stream = _getFile().getBuffer().getInputStream();
357:
358: TokenStream ts = APTTokenStreamBuilder
359: .buildTokenStream(path, stream);
360: // build apt from token stream
361: APTFile aptFull = APTBuilder.buildAPT(path, ts);
362: if (aptFull != null) {
363: storage.setAPT(aptFull);
364: APTFile aptLight = (APTFile) APTBuilder
365: .buildAPTLight(aptFull);
366: assert (aptLight != null);
367: storage.setAPTLight(aptLight);
368: out = full ? aptFull : aptLight;
369: }
370: } catch (IOException ex) {
371: APTUtils.LOG.log(Level.INFO, "create stream: {0}",
372: new Object[] { ex.getMessage() });// NOI18N
373: DiagnosticExceptoins.register(ex);
374: } finally {
375: if (stream != null) {
376: try {
377: stream.close();
378: } catch (IOException ex) {
379: APTUtils.LOG.log(Level.INFO,
380: "closing stream: {0}",
381: new Object[] { ex.getMessage() });// NOI18N
382: DiagnosticExceptoins.register(ex);
383: }
384: }
385: }
386: }
387: return out;
388: }
389: }
390:
391: ////////////////////////////////////////////////////////////////////////////
392: // load from cache files
393:
394: private Object loadLock = new Object();
395:
396: private FileCache loadValidCache() {
397: FileCache loaded = CacheManager.getInstance().loadValidCache(
398: _getFile());
399: if (loaded != null) {
400: storage.setAPT(loaded.getAPT());
401: aptMaybeOnDisk = (loaded.getAPT() != null);
402: storage.setAPTLight(loaded.getAPTLight());
403: aptLightMaybeOnDisk = (loaded.getAPTLight() != null);
404: storage.setAST(loaded.getAST(null), null);
405: astMaybeOnDisk = (loaded.getAST(null) != null);
406: }
407: return loaded;
408: }
409:
410: private String _getAbsolutePath() {
411: return absPath;
412: }
413:
414: private void _setFile(FileImpl file) {
415: this .absPath = file.getAbsolutePath();
416: this .fileUID = UIDCsmConverter.fileToUID(file);
417: }
418:
419: private FileImpl _getFile() {
420: FileImpl file = (FileImpl) UIDCsmConverter.UIDtoFile(fileUID);
421: assert (file != null);
422: return file;
423: }
424:
425: ////////////////////////////////////////////////////////////////////////////
426: // locks
427:
428: private void initLocks(String absPath) {
429: aptLock = new String("APT lock for " + absPath); // NOI18N
430: aptLightLock = new String("APT Light lock for " + absPath); // NOI18N
431: astLock = new String("AST lock for " + absPath); // NOI18N
432: }
433:
434: private String aptLock;
435: private String aptLightLock;
436: private String astLock;
437:
438: }
|