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.csm.core;
043:
044: import java.io.DataInput;
045: import java.io.DataOutput;
046: import java.io.IOException;
047: import java.util.ArrayList;
048: import java.util.HashMap;
049: import java.util.HashSet;
050: import java.util.Iterator;
051: import java.util.List;
052: import java.util.Map;
053: import java.util.Map.Entry;
054: import java.util.Set;
055: import org.netbeans.modules.cnd.api.model.CsmFile;
056: import org.netbeans.modules.cnd.api.model.CsmInclude;
057: import org.netbeans.modules.cnd.api.model.CsmProject;
058: import org.netbeans.modules.cnd.api.model.CsmUID;
059: import org.netbeans.modules.cnd.modelimpl.repository.GraphContainerKey;
060: import org.netbeans.modules.cnd.modelimpl.uid.UIDCsmConverter;
061: import org.netbeans.modules.cnd.modelimpl.uid.UIDObjectFactory;
062: import org.netbeans.modules.cnd.repository.spi.Persistent;
063: import org.netbeans.modules.cnd.repository.support.SelfPersistent;
064:
065: /**
066: * Storage for include graph.
067: * @author Alexander Simon
068: */
069: public class GraphContainer extends ProjectComponent implements
070: Persistent, SelfPersistent {
071:
072: /** Creates a new instance of GraphContainer */
073: public GraphContainer(ProjectBase project) {
074: super (new GraphContainerKey(project.getUniqueName().toString()));
075: graph = new HashMap<CsmUID<CsmFile>, NodeLink>();
076: put();
077: }
078:
079: public GraphContainer(final DataInput input) throws IOException {
080: super (input);
081: assert input != null;
082: graph = new HashMap<CsmUID<CsmFile>, NodeLink>();
083: readUIDToNodeLinkMap(input, graph);
084: }
085:
086: /**
087: * save file graph.
088: * called after (re)parse.
089: */
090: public void putFile(CsmFile master) {
091: CsmUID<CsmFile> key = UIDCsmConverter.fileToUID(master);
092: if (key != null) {
093: synchronized (graph) {
094: NodeLink node = graph.get(key);
095: if (node != null) {
096: Set<CsmUID<CsmFile>> outLink = node.getOutLinks();
097: for (CsmUID<CsmFile> out : outLink) {
098: NodeLink pair = graph.get(out);
099: if (pair != null) {
100: pair.removeInLink(key);
101: }
102: }
103: outLink.clear();
104: } else {
105: node = new NodeLink();
106: graph.put(key, node);
107: }
108: for (CsmInclude include : master.getIncludes()) {
109: CsmFile to = include.getIncludeFile();
110: if (to != null) {
111: CsmUID<CsmFile> out = UIDCsmConverter
112: .fileToUID(to);
113: NodeLink pair = graph.get(out);
114: if (pair == null) {
115: pair = new NodeLink();
116: graph.put(out, pair);
117: }
118: node.addOutLink(out);
119: pair.addInLink(key);
120: }
121: }
122: }
123: }
124: put();
125: }
126:
127: /**
128: * remove file graph.
129: * called after remove, delelete.
130: */
131: public void removeFile(CsmFile master) {
132: CsmUID<CsmFile> key = UIDCsmConverter.fileToUID(master);
133: if (key != null) {
134: synchronized (graph) {
135: NodeLink node = graph.get(key);
136: if (node != null) {
137: Set<CsmUID<CsmFile>> inLink = node.getInLinks();
138: for (CsmUID<CsmFile> in : inLink) {
139: NodeLink pair = graph.get(in);
140: if (pair != null) {
141: pair.removeOutLink(key);
142: }
143: }
144: inLink.clear();
145: Set<CsmUID<CsmFile>> outLink = node.getOutLinks();
146: for (CsmUID<CsmFile> out : outLink) {
147: NodeLink pair = graph.get(out);
148: if (pair != null) {
149: pair.removeInLink(key);
150: }
151: }
152: outLink.clear();
153: graph.remove(key);
154: }
155: }
156: }
157: put();
158: }
159:
160: /**
161: * gets all direct or indirect included files into the referenced file.
162: */
163: public Set<CsmFile> getIncludedFiles(CsmFile referencedFile) {
164: Set<CsmUID<CsmFile>> res = new HashSet<CsmUID<CsmFile>>();
165: CsmUID<CsmFile> keyFrom = UIDCsmConverter
166: .fileToUID(referencedFile);
167: if (keyFrom != null) {
168: synchronized (graph) {
169: getIncludedFiles(res, keyFrom);
170: }
171: }
172: return convertToFiles(res);
173: }
174:
175: /**
176: * gets all files that direct or indirect include the referenced file.
177: */
178: public Set<CsmFile> getParentFiles(CsmFile referencedFile) {
179: Set<CsmUID<CsmFile>> res = new HashSet<CsmUID<CsmFile>>();
180: CsmUID<CsmFile> keyTo = UIDCsmConverter
181: .fileToUID(referencedFile);
182: if (keyTo != null) {
183: synchronized (graph) {
184: getParentFiles(res, keyTo);
185: }
186: }
187: return convertToFiles(res);
188: }
189:
190: /**
191: * gets all files that direct or indirect include the referenced file.
192: * return files that not included into other files.
193: * If set empty then return set with the referenced file.
194: */
195: public Set<CsmFile> getTopParentFiles(CsmFile referencedFile) {
196: Set<CsmUID<CsmFile>> res = new HashSet<CsmUID<CsmFile>>();
197: CsmUID<CsmFile> keyTo = UIDCsmConverter
198: .fileToUID(referencedFile);
199: if (keyTo != null) {
200: synchronized (graph) {
201: getParentFiles(res, keyTo);
202: if (res.size() == 0) {
203: res.add(keyTo);
204: }
205: List<CsmUID<CsmFile>> list = new ArrayList<CsmUID<CsmFile>>(
206: res);
207: res.clear();
208: for (CsmUID<CsmFile> uid : list) {
209: NodeLink link = graph.get(uid);
210: if (link != null && link.getInLinks().size() == 0) {
211: res.add(uid);
212: }
213: }
214: }
215: }
216: return convertToFiles(res);
217: }
218:
219: /**
220: * gets all files that direct or indirect include referenced file.
221: * If set empty then return set with the referenced file.
222: */
223: public Set<CsmFile> getCoherenceFiles(CsmFile referencedFile) {
224: CsmProject project = referencedFile.getProject();
225: Set<CsmUID<CsmFile>> res = new HashSet<CsmUID<CsmFile>>();
226: CsmUID<CsmFile> keyTo = UIDCsmConverter
227: .fileToUID(referencedFile);
228: if (keyTo != null) {
229: synchronized (graph) {
230: getParentFiles(res, keyTo);
231: if (res.size() == 0) {
232: res.add(keyTo);
233: }
234: for (CsmUID<CsmFile> uid : new ArrayList<CsmUID<CsmFile>>(
235: res)) {
236: getIncludedFiles(res, uid);
237: }
238: }
239: }
240: return convertToFiles(res);
241: }
242:
243: /**
244: * Returns set files that direct include referenced file.
245: */
246: public Set<CsmFile> getInLinks(CsmFile referencedFile) {
247: Set<CsmUID<CsmFile>> res = new HashSet<CsmUID<CsmFile>>();
248: CsmUID<CsmFile> keyTo = UIDCsmConverter
249: .fileToUID(referencedFile);
250: if (keyTo != null) {
251: synchronized (graph) {
252: NodeLink node = graph.get(keyTo);
253: if (node != null) {
254: for (CsmUID<CsmFile> uid : node.getInLinks()) {
255: if (!res.contains(uid)) {
256: res.add(uid);
257: }
258: }
259: }
260: }
261: }
262: return convertToFiles(res);
263: }
264:
265: /**
266: * Returns set of direct included files in the referenced file.
267: */
268: public Set<CsmFile> getOutLinks(CsmFile referencedFile) {
269: Set<CsmUID<CsmFile>> res = new HashSet<CsmUID<CsmFile>>();
270: CsmUID<CsmFile> keyTo = UIDCsmConverter
271: .fileToUID(referencedFile);
272: if (keyTo != null) {
273: synchronized (graph) {
274: NodeLink node = graph.get(keyTo);
275: if (node != null) {
276: for (CsmUID<CsmFile> uid : node.getOutLinks()) {
277: if (!res.contains(uid)) {
278: res.add(uid);
279: }
280: }
281: }
282: }
283: }
284: return convertToFiles(res);
285: }
286:
287: private Set<CsmFile> convertToFiles(Set<CsmUID<CsmFile>> res) {
288: Set<CsmFile> res2 = new HashSet<CsmFile>();
289: for (CsmUID<CsmFile> uid : res) {
290: CsmFile file = UIDCsmConverter.UIDtoFile(uid);
291: if (file != null) {
292: res2.add(file);
293: }
294: }
295: return res2;
296: }
297:
298: /*
299: * method called in synchronized block
300: */
301: private void getIncludedFiles(Set<CsmUID<CsmFile>> res,
302: CsmUID<CsmFile> keyFrom) {
303: NodeLink node = graph.get(keyFrom);
304: if (node != null) {
305: for (CsmUID<CsmFile> uid : node.getOutLinks()) {
306: if (!res.contains(uid)) {
307: res.add(uid);
308: getIncludedFiles(res, uid);
309: }
310: }
311: }
312: }
313:
314: /*
315: * method called in synchronized block
316: */
317: private void getParentFiles(Set<CsmUID<CsmFile>> res,
318: CsmUID<CsmFile> keyTo) {
319: NodeLink node = graph.get(keyTo);
320: if (node != null) {
321: for (CsmUID<CsmFile> uid : node.getInLinks()) {
322: if (!res.contains(uid)) {
323: res.add(uid);
324: getParentFiles(res, uid);
325: }
326: }
327: }
328: }
329:
330: public void clear() {
331: synchronized (graph) {
332: graph.clear();
333: }
334: put();
335: }
336:
337: @Override
338: public void write(DataOutput output) throws IOException {
339: super .write(output);
340: synchronized (graph) {
341: writeUIDToNodeLinkMap(output, graph);
342: }
343: }
344:
345: private static void writeUIDToNodeLinkMap(final DataOutput output,
346: final Map<CsmUID<CsmFile>, NodeLink> aMap)
347: throws IOException {
348:
349: assert output != null;
350: assert aMap != null;
351:
352: UIDObjectFactory uidFactory = UIDObjectFactory
353: .getDefaultFactory();
354: assert uidFactory != null;
355:
356: output.writeInt(aMap.size());
357:
358: final Set<Entry<CsmUID<CsmFile>, NodeLink>> entrySet = aMap
359: .entrySet();
360: final Iterator<Entry<CsmUID<CsmFile>, NodeLink>> setIterator = entrySet
361: .iterator();
362:
363: while (setIterator.hasNext()) {
364: final Entry<CsmUID<CsmFile>, NodeLink> anEntry = setIterator
365: .next();
366: assert anEntry != null;
367:
368: uidFactory.writeUID(anEntry.getKey(), output);
369: anEntry.getValue().write(output);
370: }
371: }
372:
373: private static void readUIDToNodeLinkMap(final DataInput input,
374: Map<CsmUID<CsmFile>, NodeLink> aMap) throws IOException {
375:
376: assert input != null;
377: assert aMap != null;
378: UIDObjectFactory uidFactory = UIDObjectFactory
379: .getDefaultFactory();
380: assert uidFactory != null;
381:
382: aMap.clear();
383:
384: final int size = input.readInt();
385:
386: for (int i = 0; i < size; i++) {
387: final CsmUID<CsmFile> uid = uidFactory.readUID(input);
388: final NodeLink link = new NodeLink(input);
389:
390: assert uid != null;
391: assert link != null;
392:
393: aMap.put(uid, link);
394: }
395:
396: }
397:
398: private Map<CsmUID<CsmFile>, NodeLink> graph;
399:
400: private static class NodeLink implements SelfPersistent, Persistent {
401:
402: Set<CsmUID<CsmFile>> in = new HashSet<CsmUID<CsmFile>>();
403: Set<CsmUID<CsmFile>> out = new HashSet<CsmUID<CsmFile>>();
404:
405: private NodeLink() {
406: }
407:
408: private NodeLink(final DataInput input) throws IOException {
409: assert input != null;
410: assert in != null;
411: assert out != null;
412:
413: final UIDObjectFactory factory = UIDObjectFactory
414: .getDefaultFactory();
415: assert factory != null;
416:
417: factory.readUIDCollection(in, input);
418: factory.readUIDCollection(out, input);
419: }
420:
421: private void addInLink(CsmUID<CsmFile> inLink) {
422: in.add(inLink);
423: }
424:
425: private void removeInLink(CsmUID<CsmFile> inLink) {
426: in.remove(inLink);
427: }
428:
429: private Set<CsmUID<CsmFile>> getInLinks() {
430: return in;
431: }
432:
433: private void addOutLink(CsmUID<CsmFile> inLink) {
434: out.add(inLink);
435: }
436:
437: private void removeOutLink(CsmUID<CsmFile> inLink) {
438: out.remove(inLink);
439: }
440:
441: private Set<CsmUID<CsmFile>> getOutLinks() {
442: return out;
443: }
444:
445: public void write(final DataOutput output) throws IOException {
446: assert output != null;
447: assert in != null;
448: assert out != null;
449:
450: final UIDObjectFactory factory = UIDObjectFactory
451: .getDefaultFactory();
452: assert factory != null;
453:
454: factory.writeUIDCollection(in, output, false);
455: factory.writeUIDCollection(out, output, false);
456: }
457: }
458:
459: }
|