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.List;
035    import java.util.Map;
036    
037    import javax.swing.WindowConstants;
038    import javax.swing.tree.TreeNode;
039    
040    import org.mesopotamia.sql.LoadError;
041    import org.mesopotamia.sql.MesopotamiaEngine;
042    import org.w3c.dom.Element;
043    
044    import biz.hammurapi.config.Context;
045    import biz.hammurapi.convert.ConvertingService;
046    import biz.hammurapi.legacy.review.Signed;
047    import biz.hammurapi.render.HtmlRenderer;
048    import biz.hammurapi.swing.Browser;
049    import biz.hammurapi.swing.Visualizable;
050    import biz.hammurapi.util.Attributable;
051    import biz.hammurapi.util.VisitableBase;
052    import biz.hammurapi.xml.dom.DomSerializable;
053    
054    
055    /**
056     * Represents source unit, e.g. java source file
057     * @author Pavel Vlasov
058     * @revision $Revision: 1.1 $
059     */
060    public class SourceUnit extends VisitableBase implements DomSerializable, Signed, Attributable {
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<String, Reference> levelData = new HashMap<String, Reference>();
069            
070            /**
071             * Set of level at which this unit is loaded.
072             */
073            private Collection<Number> loadLevels = new ArrayList<Number>();
074    
075            /**
076             * Instances of SourceUnit shall be created only by
077             * repository
078             * @throws SQLException 
079             */
080            protected SourceUnit(org.mesopotamia.sql.SourceUnit dbData, final Scan scan, RepositoryLanguage repoLanguage, Collection<Number> loadLevels) throws MesopotamiaException {
081                    this.repoLanguage=repoLanguage;
082                    this.scan=scan;
083                    this.dbData=dbData;
084                    
085                    Iterator<Number> it = loadLevels.iterator();
086                    while (it.hasNext()) {
087                            this.loadLevels.add(it.next());
088                            
089                    }               
090                    MesopotamiaEngine engine = scan.getRepository().getFactory().getEngine();               
091                    try {
092                            errors=Collections.unmodifiableCollection(engine.getLoadError(dbData.getId(), scan.getId(), new ArrayList<LoadError>()));
093                    } catch (SQLException e) {
094                            throw new MesopotamiaException("Could not load errors: "+e, e);
095                    }
096            }
097            
098            static final List<Object> EMPTY_UNMODIFIABLE_LIST = Collections.unmodifiableList(new ArrayList());
099    
100            public int getId() {
101                    return dbData.getId();
102            }
103    
104            public String getName() {
105                    return dbData.getName();
106            }
107    
108            /**
109             * Namespace shall be retrieved from repository
110             * @return
111             */
112            public Namespace getNamespace() {
113                    return scan.getNamespace(dbData.getNamespaceId());
114            }
115    
116            public String getPath() {
117                    return dbData.getPath();
118            }
119    
120            public String getDigest() {
121                    return dbData.getUnitDigest();
122            }
123    
124            public Long getSize() {
125                    return dbData.getUnitSize();
126            }
127            
128            public RepositoryLanguage getLanguage() {
129                    return repoLanguage;
130            }
131    
132            public Scan getScan() {
133                    return scan;
134            }
135    
136            public void toDom(Element holder) {
137                    holder.setAttribute("digest-algorithm", dbData.getDigestAlgorithm());
138                    holder.setAttribute("id", String.valueOf(dbData.getId()));
139                    holder.setAttribute("language", dbData.getLanguage());
140                    holder.setAttribute("language-version", dbData.getLanguageVersion());
141                    if (dbData.getLastModified()!=null) {
142                            holder.setAttribute("last-modified", dbData.getLastModified().toString());
143                    }
144                    holder.setAttribute("name", dbData.getName());
145                    holder.setAttribute("path", dbData.getPath());
146                    holder.setAttribute("repository", String.valueOf(dbData.getRepositoryId()));
147                    if (dbData.getUnitSize()!=null) {
148                            holder.setAttribute("size", dbData.getUnitSize().toString());
149                    }
150                    if (dbData.getUnitDigest()!=null) {
151                            holder.setAttribute("digest", dbData.getUnitDigest());
152                    }               
153            }
154    
155            /**
156             * Returns signature, which is path.
157             */
158            public String getSignature() {
159                    return getPath();
160            }
161            
162            /**
163             * @return load levels of this source unit. Elements are of type org.mesopotamia.sql.SourceUnitSuccessfulLoadLevels
164             */
165            public Collection<Number> getLoadLevels() {
166                    return loadLevels;
167            }
168            
169            public String toString() {
170                    return "["+getClass().getName()+"] "+getPath();
171            }
172            
173            private Collection<LoadError> errors;
174            
175            public Collection<LoadError> getErrors() {
176                    return errors;
177            }
178            
179            /**
180             * @param levelName
181             * @return Load level data for given source unit. This method returns only 
182             * scan-independent data.
183             * @throws MesopotamiaException 
184             */
185            public Object getLevelData(String levelName) {
186                    synchronized (levelData) {
187                            try {
188                                    Reference<Object> ref = levelData.get(levelName);
189                                    Object ret = ref==null ? null : ref.get();
190                                    if (ret==null) {
191                                            ret = getLanguage().getLoader(levelName).getData(getId(), null);
192                                            ref = new SoftReference<Object>(ret);
193                                            levelData.put(levelName, ref);
194                                    }                                               
195                                    return ret;
196                            } catch (MesopotamiaException e) {
197                                    throw new MesopotamiaRuntimeException(e);
198                            }
199                    }
200            }
201            
202            /**
203             * Shows source unit in browser. Use it for debugging.
204             */
205            public void show() {
206                    Visualizable vs = (Visualizable) ConvertingService.convert(this, Visualizable.class); 
207                    TreeNode root = vs.toTreeNode(null, "Source unit");
208                    
209                    final Object monitor = new Object();
210                    
211                    Browser browser = new Browser("Source unit "+getId(), root) {
212                            
213                            protected void processWindowEvent(WindowEvent e) {
214                                    super.processWindowEvent(e);
215                                    if (e.getID()==WindowEvent.WINDOW_CLOSED) {
216                                            synchronized (monitor) {
217                                                    monitor.notifyAll();
218                                            }
219                                    }
220                            }
221                    };
222                    
223                    browser.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
224                    browser.setVisible(true);
225                    
226                    synchronized (monitor) {
227                            try {
228                                    monitor.wait();
229                            } catch (InterruptedException ex) {
230                                    // Ignore
231                            }
232                    }
233    
234            }
235            
236            private Map<Object, Object> attributes = new HashMap<Object, Object>();
237    
238            public Object getAttribute(Object key) {
239                    return attributes.get(key);
240            }
241    
242            public Object removeAttribute(Object key) {
243                    return attributes.remove(key);
244            }
245    
246            public void setAttribute(Object key, Object value) {
247                    attributes.put(key, value);             
248            }
249            
250            /**
251             * Returns renderer to render this source unit to HTML.
252             * @param context Renderer configuration parameters.
253             * @return renderer or null if source unit does not support
254             * rendering.
255             */
256            public HtmlRenderer getRenderer(Context context) {
257                    return null;
258            }
259    }