001: /*
002: * mesopotamia @mesopotamia.version@
003: * Multilingual parser and repository.
004: * Copyright (C) 2005 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://http://www.hammurapi.biz
021: * e-Mail: support@hammurapi.biz
022: */
023: package org.mesopotamia;
024:
025: import java.awt.event.WindowEvent;
026: import java.lang.ref.Reference;
027: import java.lang.ref.SoftReference;
028: import java.sql.SQLException;
029: import java.util.ArrayList;
030: import java.util.Collection;
031: import java.util.Collections;
032: import java.util.HashMap;
033: import java.util.Iterator;
034: import java.util.Map;
035:
036: import javax.swing.WindowConstants;
037:
038: import org.mesopotamia.sql.MesopotamiaEngine;
039: import org.mesopotamia.util.MesopotamiaVisualizer;
040: import org.w3c.dom.Element;
041:
042: import biz.hammurapi.convert.Converter;
043: import biz.hammurapi.legacy.review.Signed;
044: import biz.hammurapi.swing.Browser;
045: import biz.hammurapi.swing.CompositeVisualizer;
046: import biz.hammurapi.swing.Visualizable;
047: import biz.hammurapi.util.CollectionVisitable;
048: import biz.hammurapi.util.ConvertingCollection;
049: import biz.hammurapi.util.VisitableBase;
050: import biz.hammurapi.util.Visitor;
051: import biz.hammurapi.xml.dom.CompositeDomSerializer;
052: import biz.hammurapi.xml.dom.DomSerializable;
053:
054: /**
055: * Represents source unit, e.g. java source file
056: * @author Pavel Vlasov
057: * @revision $Revision: 1.1 $
058: */
059: public class SourceUnit extends VisitableBase implements
060: DomSerializable, Signed {
061: Scan scan;
062: RepositoryLanguage repoLanguage;
063: private org.mesopotamia.sql.SourceUnit dbData;
064:
065: /**
066: * Map of level name -> Soft reference -> level data
067: */
068: private Map levelData = new HashMap();
069:
070: private Collection languageElements;
071:
072: /**
073: * Set of level at which this unit is loaded.
074: */
075: private Collection loadLevels = new ArrayList();
076:
077: /**
078: * Instances of SourceUnit shall be created only by
079: * repository
080: * @throws SQLException
081: */
082: SourceUnit(org.mesopotamia.sql.SourceUnit dbData, final Scan scan,
083: RepositoryLanguage repoLanguage, Collection loadLevels)
084: throws MesopotamiaException {
085: this .repoLanguage = repoLanguage;
086: this .scan = scan;
087: this .dbData = dbData;
088:
089: Iterator it = loadLevels.iterator();
090: while (it.hasNext()) {
091: this .loadLevels.add(it.next());
092:
093: }
094: MesopotamiaEngine engine = scan.getRepository().getFactory()
095: .getEngine();
096: try {
097: errors = Collections.unmodifiableCollection(engine
098: .getLoadError(dbData.getId(), scan.getId(),
099: new ArrayList()));
100: } catch (SQLException e) {
101: throw new MesopotamiaException("Could not load errors: "
102: + e, e);
103: }
104:
105: SyntaxTree st = getSyntaxTree();
106: if (st == null) {
107: languageElements = EMPTY_UNMODIFIABLE_COLLECTION;
108: } else {
109: ConvertingCollection rootLanguageElements = new ConvertingCollection(
110: st.getRoots(), new Converter() {
111:
112: public Object convert(Object source) {
113: NodeData mn = (NodeData) source;
114: LanguageElementHandle handle = new LanguageElementHandle(
115: mn.getSourceUnitId(), mn.getId(),
116: null, null);
117: return scan.getLanguageElement(handle);
118: }
119:
120: }, null);
121:
122: languageElements = Collections
123: .unmodifiableCollection(rootLanguageElements);
124: }
125: }
126:
127: static final Collection EMPTY_UNMODIFIABLE_COLLECTION = Collections
128: .unmodifiableCollection(new ArrayList());
129:
130: public SyntaxTree getSyntaxTree() {
131: return (SyntaxTree) getLevelData("ast");
132: }
133:
134: public int getId() {
135: return dbData.getId();
136: }
137:
138: public String getName() {
139: return dbData.getName();
140: }
141:
142: /**
143: * Namespace shall be retrieved from repository
144: * @return
145: */
146: public Namespace getNamespace() {
147: return scan.getNamespace(dbData.getNamespaceId());
148: }
149:
150: public String getPath() {
151: return dbData.getPath();
152: }
153:
154: public String getDigest() {
155: return dbData.getUnitDigest();
156: }
157:
158: public Long getSize() {
159: return dbData.getUnitSize();
160: }
161:
162: protected void acceptChildren(Visitor visitor) {
163: // TODO - Visit loader data. Use object2Visitable.
164: // tokens=engine.getSourceUnitTokens(
165: // dbData.getId(),
166: // new ArrayList(),
167: // new Converter() {
168: //
169: // public Object convert(Object source) {
170: // return new Token(scan, (SourceUnitToken) source);
171: // }
172: //
173: // });
174: //
175: // new CollectionVisitable(tokens, false).accept(visitor);
176: new CollectionVisitable(languageElements, false)
177: .accept(visitor);
178: }
179:
180: /**
181: * @return Root language elements
182: */
183: public Collection getLanguageElements() {
184: return languageElements;
185: }
186:
187: public RepositoryLanguage getLanguage() {
188: return repoLanguage;
189: }
190:
191: public Scan getScan() {
192: return scan;
193: }
194:
195: public void toDom(Element holder) {
196: holder.setAttribute("digest-algorithm", dbData
197: .getDigestAlgorithm());
198: holder.setAttribute("id", String.valueOf(dbData.getId()));
199: holder.setAttribute("language", dbData.getLanguage());
200: holder.setAttribute("language-version", dbData
201: .getLanguageVersion());
202: if (dbData.getLastModified() != null) {
203: holder.setAttribute("last-modified", dbData
204: .getLastModified().toString());
205: }
206: holder.setAttribute("name", dbData.getName());
207: holder.setAttribute("path", dbData.getPath());
208: holder.setAttribute("repository", String.valueOf(dbData
209: .getRepositoryId()));
210: if (dbData.getUnitSize() != null) {
211: holder
212: .setAttribute("size", dbData.getUnitSize()
213: .toString());
214: }
215: if (dbData.getUnitDigest() != null) {
216: holder.setAttribute("digest", dbData.getUnitDigest());
217: }
218:
219: // TODO - implement for tokens, e.t.c.
220: // Iterator it=loadLevels.keySet().iterator();
221: // while (it.hasNext()) {
222: // String level = (String) it.next();
223: // Object levelData = getLevelData(level);
224: // if (levelData!=null) {
225: // Element levelElement=holder.getOwnerDocument().createElement("level");
226: // holder.appendChild(levelElement);
227: // CompositeDomSerializer.getThreadInstance().toDomSerializable(levelData).toDom(levelElement);
228: // }
229: // }
230:
231: Element le = holder.getOwnerDocument().createElement(
232: "language-elements");
233: holder.appendChild(le);
234: CompositeDomSerializer.getThreadInstance().toDomSerializable(
235: languageElements).toDom(le);
236:
237: }
238:
239: /**
240: * Returns signature, which is path.
241: */
242: public String getSignature() {
243: return getPath();
244: }
245:
246: /**
247: * @return load levels of this source unit. Elements are of type org.mesopotamia.sql.SourceUnitSuccessfulLoadLevels
248: */
249: public Collection getLoadLevels() {
250: return loadLevels;
251: }
252:
253: public String toString() {
254: return "[" + getClass().getName() + "] " + getPath();
255: }
256:
257: private Collection errors;
258:
259: public Collection getErrors() {
260: return errors;
261: }
262:
263: public Token getToken(int position) {
264: return (Token) ((ArrayList) getLevelData("token"))
265: .get(position);
266: }
267:
268: /**
269: * @param levelName
270: * @return Load level data for given source unit. This method returns only
271: * scan-independent data.
272: * @throws MesopotamiaException
273: */
274: public Object getLevelData(String levelName) {
275: synchronized (levelData) {
276: try {
277: Reference ref = (Reference) levelData.get(levelName);
278: Object ret = ref == null ? null : ref.get();
279: if (ret == null) {
280: ret = getLanguage().getLoader(levelName).getData(
281: getId(), null);
282: ref = new SoftReference(ret);
283: levelData.put(levelName, ref);
284: }
285: return ret;
286: } catch (MesopotamiaException e) {
287: throw new MesopotamiaRuntimeException(e);
288: }
289: }
290: }
291:
292: /**
293: * Shows source unit in browser. Use it for debugging.
294: */
295: public void show() {
296: CompositeVisualizer cv = CompositeVisualizer
297: .getThreadInstance();
298: cv.addVisualizer(new MesopotamiaVisualizer());
299: Visualizable v = cv.toVisualizable(this );
300:
301: final Object monitor = new Object();
302:
303: Browser browser = new Browser("Source unit " + getId(), v
304: .toTree(null)) {
305:
306: protected void processWindowEvent(WindowEvent e) {
307: super .processWindowEvent(e);
308: if (e.getID() == WindowEvent.WINDOW_CLOSED) {
309: synchronized (monitor) {
310: monitor.notifyAll();
311: }
312: }
313: }
314: };
315:
316: browser
317: .setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
318: browser.setVisible(true);
319:
320: synchronized (monitor) {
321: try {
322: monitor.wait();
323: } catch (InterruptedException ex) {
324: // Ignore
325: }
326: }
327:
328: }
329:
330: }
|