Scan.java :  » Parser » mesopotamia » org » mesopotamia » Java Open Source

Java Open Source » Parser » mesopotamia 
mesopotamia » org » mesopotamia » Scan.java
/*
 * mesopotamia @mesopotamia.version@
 * Multilingual parser and repository. 
 * Copyright (C) 2005  Hammurapi Group
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * URL: http://http://www.hammurapi.biz
 * e-Mail: support@hammurapi.biz
 */
package org.mesopotamia;

import gnu.trove.TIntHashSet;

import java.awt.event.WindowEvent;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import javax.swing.WindowConstants;

import org.mesopotamia.sql.MesopotamiaEngine;
import org.mesopotamia.util.MesopotamiaVisualizer;

import biz.hammurapi.cache.Cache;
import biz.hammurapi.cache.Entry;
import biz.hammurapi.cache.MemoryCache;
import biz.hammurapi.cache.Producer;
import biz.hammurapi.convert.Converter;
import biz.hammurapi.metrics.MeasurementCategory;
import biz.hammurapi.metrics.MeasurementCategoryFactory;
import biz.hammurapi.sql.IdentityGenerator;
import biz.hammurapi.sql.IdentityManager;
import biz.hammurapi.sql.IdentityRetriever;
import biz.hammurapi.sql.SQLProcessor;
import biz.hammurapi.sql.Transaction;
import biz.hammurapi.swing.Browser;
import biz.hammurapi.swing.CompositeVisualizer;
import biz.hammurapi.swing.Visualizable;
import biz.hammurapi.util.CollectionVisitable;
import biz.hammurapi.util.ConvertingCollection;
import biz.hammurapi.util.VisitableBase;
import biz.hammurapi.util.Visitor;


public class Scan extends VisitableBase {
  private static final MeasurementCategory mc=MeasurementCategoryFactory.getCategory(Repository.class);
  
  private Repository repository;
  private org.mesopotamia.sql.Scan dbData;

  Object environment;

  private class SourceUnitProducer implements Producer {

    public Entry get(Object key) {
      Integer sid=(Integer) key;
      MesopotamiaEngine engine=repository.getFactory().getEngine();
      try {      
        org.mesopotamia.sql.SourceUnit dbData=engine.getSourceUnit(sid.intValue());
        if (dbData==null) {
          throw new MesopotamiaRuntimeException("Invalid source unit ID: "+sid);
        }
        
        RepositoryLanguage repoLanguage=repository.getFactory().getRepositoryLanguage(new Language(dbData.getLanguage(), dbData.getLanguageVersion(), null));
        if (repoLanguage==null) {
          throw new MesopotamiaRuntimeException("Language not found: "+dbData.getLanguage()+" "+dbData.getLanguageVersion());
        }
        
        final SourceUnit su = repoLanguage.instantiateSourceUnit(dbData, Scan.this);

        return new Entry() {

          public long getExpirationTime() {
            return 0;
          }

          public long getTime() {
            return 0;
          }

          public Object get() {
            return su;
          }
          
        };
      } catch (SQLException e) {
        throw new MesopotamiaRuntimeException("Cannot instantiate source unit", e);
      }
    }

    public void addCache(Cache cache) {
      // Empty method
    }

    public Set keySet() {
      // Empty method
      return null;
    }
    
  }
  
  private class LanguageElementProducer implements Producer {
    
    public Entry get(Object key) {
      LanguageElementHandle lek=(LanguageElementHandle) key;
      SourceUnit su = getSourceUnit(lek.getSourceUnitId());
      if (su==null) {
        throw new MesopotamiaRuntimeException("Invalid source unit ID: "+lek.getSourceUnitId());
      }
      
      SyntaxTree st = (SyntaxTree) su.getLevelData("ast");
      if (st==null) {
        throw new MesopotamiaRuntimeException("Source unit "+lek.getSourceUnitId()+" is not loaded at level ast");
      }
      
      org.mesopotamia.MesopotamiaNode xData=st.findNode(lek.getId());
      if (xData==null) {
        throw new MesopotamiaRuntimeException("Invalid language element ID: "+lek.getId());
      }
      
      RepositoryLanguage repoLanguage=repository.getFactory().getRepositoryLanguageByTokenTypeId(xData.getType());
      if (repoLanguage==null) {
        throw new MesopotamiaRuntimeException("Language not found for token type id: "+xData.getType());
      }
      
      final LanguageElement le = repoLanguage.instantiateLanguageElement(xData, lek.getContextClass(), lek.getTargetClass(), Scan.this);

      return new Entry() {

        public long getExpirationTime() {
          return 0;
        }

        public long getTime() {
          return 0;
        }

        public Object get() {
          return le;
        }
        
      };
    }

    public void addCache(Cache cache) {
      // Empty method
      
    }

    public Set keySet() {
      // Empty method
      return null;
    }
    
  }
  
  /**
   * Repository is instantiated only by RepositoryFactory
   * @param environment 
   * @param checkSumName 
   * @param selector 
   * @param sourceIterator 
   * @param listener 
   * @param factory
   * @param language
   * @param languageVersion
   * @param name
   */
  Scan(
      Repository repository, 
      org.mesopotamia.sql.Scan dbData, 
      SourceIterator sourceIterator, 
      LanguageSelector selector, 
      String checkSumAlgorithm, 
      final Object environment,
      final LoadListener listener) 
      throws MesopotamiaException {
    this(repository, dbData);
    this.environment=environment;
    
    if (listener!=null) {
      listener.onScanStarted(dbData.getId());
    }
    
    final RepositoryFactory factory = repository.getFactory();
    
    int sourceCounter=0;
    Source s;
    while ((s=sourceIterator.nextSource())!=null) {
      Language language = selector.select(s);
      if (language==null) {
        continue; // No language associated with extension
      }
      
      final RepositoryLanguage repoLanguage = factory.getRepositoryLanguage(language);
      
      if (repoLanguage==null) {
        continue; // Given language is not defined in the repository
      }
      
      ++sourceCounter;
      
      final SourceLink sl=linkSource(repoLanguage, s, checkSumAlgorithm);
      final int scanId = Scan.this.dbData.getId();
      
      Iterator lit=repoLanguage.getLoaders().iterator();
      while (lit.hasNext()) {
        final LoaderEntry le = (LoaderEntry) lit.next();
        final String levelName = le.getLevel();
        
        if (sl.loadLevels.contains(le.getId())) { 
          listener.onLink(scanId, sl.sourceId, levelName);            
        }         
      }

      // TODO - in the future analyze which levels are not yet loaded
      // and invoke load only if there are unloaded levels.
      // it is done in load() anyway
      repoLanguage.load(scanId, sl.sourceId, s, environment, listener);
    }
    
    if (listener!=null) {
      listener.onScanFinished(dbData.getId(), sourceCounter);
    }    
  }
  
  /**
   * Repository is instantiated only by RepositoryFactory
   * @param environment 
   * @param checkSumName 
   * @param selector 
   * @param sourceIterator 
   * @param listener 
   * @param factory
   * @param language
   * @param languageVersion
   * @param name
   */
  Scan(final Repository repository, org.mesopotamia.sql.Scan dbData) {    
    this.repository=repository;
    this.dbData=dbData;
    
    languageElementsCache=new MemoryCache(
        new LanguageElementProducer(), 
        null, 
        mc,
        repository.getFactory().getTimer(),
        MemoryCache.CLEANUP_INTERVAL);
    
    sourceUnitCache=new MemoryCache(
        new SourceUnitProducer(), 
        null, 
        mc,
        repository.getFactory().getTimer(),
        MemoryCache.CLEANUP_INTERVAL);
    
    sourceUnitLoadLevelsCache=new MemoryCache(
        new Producer() {

          public Entry get(Object key) {
            try {
              final Collection value = repository.getFactory().getEngine().getSourceUnitSuccessfulLoadLevels(
                  ((Number) key).intValue(), 
                  getId(), 
                  new HashSet(),
                  repository.getFactory().levelIdToIntegerConverter);
              
              return new Entry() {

                public long getExpirationTime() {
                  return 0;
                }

                public long getTime() {
                  return 0;
                }

                public Object get() {
                  return value;
                }
                
              };
            } catch (SQLException e) {
              throw new MesopotamiaRuntimeException("Cannol retrieve source unit load levels from the database", e);
            }
          }

          public void addCache(Cache cache) {
            // Empty method          
          }

          public Set keySet() {
            // Empty method
            return null;
          }
          
        }, 
        null,
        mc,
        repository.getFactory().getTimer(),
        MemoryCache.CLEANUP_INTERVAL);

  }
  
  private class SourceLink {
    Source source;
    int sourceId;
    public TIntHashSet loadLevels;
  }
  
  /**
   * @param sources
   * @param digestAlgorithm
   * @param factory
   * @throws MesopotamiaException
   */
  private SourceLink linkSource(
      RepositoryLanguage repoLanguage, 
      Source source, 
      String digestAlgorithm) throws MesopotamiaException {
    try {      
      final RepositoryFactory factory = repoLanguage.getFactory();
      String digest = source.getDigest(factory.getMessageDigest(digestAlgorithm));
      final org.mesopotamia.sql.SourceUnit[] su = {factory.getEngine().getExistingSourceUnit(
          repository.getId(),
          source.getSize(),
          digest,
          source.getPath())};
      
      TIntHashSet loadLevels=new TIntHashSet();
      if (su[0]==null) {          
        // TODO - For changed source set reference to previous revision
        su[0]=new org.mesopotamia.sql.SourceUnitImpl(true);
        su[0].setDigestAlgorithm(digestAlgorithm);
        su[0].setName(source.getName());
        su[0].setPath(source.getPath());
        su[0].setUnitDigest(digest);
        su[0].setUnitSize(new Long(source.getSize()));
        su[0].setLastModified(new Timestamp(source.getLastModified()));
        su[0].setLanguage(repoLanguage.getName());
        su[0].setLanguageVersion(repoLanguage.getVersion());
        su[0].setRepositoryId(repository.getId());
      
        factory.getProcessor().executeTransaction(new Transaction() {
          
          public boolean execute(SQLProcessor processor) throws SQLException {          
            IdentityManager identityManager = factory.getIdentityManager();
            if (identityManager instanceof IdentityGenerator) {
              su[0].setId(((IdentityGenerator) identityManager).generate(processor.getConnection(), "REPOSITORY"));
            }
            new MesopotamiaEngine(processor).insertSourceUnit(su[0]);
            if (identityManager instanceof IdentityRetriever) {
              su[0].setId(((IdentityRetriever) identityManager).retrieve(processor.getConnection()));
            }
                        
            return true;
          }
          
        });
      }
      
      factory.getEngine().insertSourceUnitScan(getId(), su[0].getId());
      SourceLink sl=new SourceLink();
      sl.source=source;
      sl.sourceId=su[0].getId();
      sl.loadLevels=loadLevels;
      return sl;
    } catch (SQLException e) {
      throw new MesopotamiaException(e);
    }      
  }

  // Should be instantiated by repository
  // dbData - Scan, expose its accessors through
  // delegation
  
  protected void acceptChildren(Visitor visitor) {
    try {
      new CollectionVisitable(getSourceUnits(), false).accept(visitor);
    } catch (MesopotamiaException e) {
      throw new MesopotamiaRuntimeException(e);
    }
    // For languages which do not support namespaces
    // or where one source unit can contain multiple
    // namespaces (C++)
    // iterate through source units
    // otherwise iterate through namespaces
    // which will iterate through source units 
    
    // TODO Auto-generated method stub
  }



  public String getDescription() {
    return dbData.getDescription();
  }



  public int getId() {
    return dbData.getId();
  }



  public Repository getRepository() {
    return repository;
  }



  public Timestamp getScanDate() {
    return dbData.getScanDate();
  }



  public void setDescription(String description) {
    dbData.setDescription(description);
  }

  public void delete() throws MesopotamiaException {
    MesopotamiaEngine engine = repository.getFactory().getEngine();
    try {
      engine.deleteSourceUnitScanByScan(getId());
      engine.deleteScan(getId());
      engine.deleteOrphanSourceUnits(repository.getId());
    } catch (SQLException e) {
      throw new MesopotamiaException("Scan detetion failed: "+e, e);
    }
  }  
  
  /**
   * Memory cache is a front-end for language elment producer.  
   * This approach guarantees that at any point of time there is only one
   * instance of a particular language element in memory
   */
  private MemoryCache languageElementsCache;
  
  /**
   * Memory cache is a front-end for source unit producer.  
   * This approach guarantees that at any point of time there is only one
   * instance of a particular source unit in memory
   */
  private MemoryCache sourceUnitCache;
    
  
  public LanguageElement getLanguageElement(LanguageElementHandle handle) {
    if (handle==null) {
      return null;
    }
    
    Entry e=languageElementsCache.get(handle);
    LanguageElement ret = (LanguageElement) (e==null ? null : e.get());
//    if (ret!=null && ret.getSourceUnit().getId()!=handle.getSourceUnitId()) {
//      throw new IllegalArgumentException("Handle and return are from different source units, "+handle+", "+ret);
//    }
    
    return ret;
  }

  public SourceUnit getSourceUnit(int sourceUnitId) {
    Entry e=sourceUnitCache.get(new Integer(sourceUnitId));
    return (SourceUnit) (e==null ? null : e.get());
  }
  
  private Collection sourceUnits;
  
  public Collection getSourceUnits() throws MesopotamiaException {
    if (sourceUnits==null) {
      try {
        Collection suIds = repository.getFactory().getEngine().getSourceUnitsInScan(
            dbData.getId(),
            new ArrayList(),
            repository.getFactory().toIntegerConverter);
        
        sourceUnits=Collections.unmodifiableCollection(
            new ConvertingCollection(
                suIds,
                new Converter() {

                  public Object convert(Object source) {
                    return getSourceUnit(((Number) source).intValue());
                  }
                  
                }, 
                new Converter() {

                  public Object convert(Object source) {
                    return new Integer(((SourceUnit) source).getId());
                  }
                  
                }));
      } catch (SQLException e) {
        throw new MesopotamiaException("Cannot load source unit id's", e);
      }
      
    }
    return sourceUnits;
  }

  /**
   * Shuts down language element and source unit caches
   */
  public void stop() {
    languageElementsCache.stop();
    sourceUnitCache.stop();
    sourceUnitLoadLevelsCache.stop();
  }
  
  public Namespace getNamespace(Integer namespaceId) {
    // TODO Auto-generated method stub
    return null;
  }
  
  private MemoryCache sourceUnitLoadLevelsCache;
  
  public Collection getSourceUnitLoadLevels(int id) {
    return (Collection) sourceUnitLoadLevelsCache.get(new Integer(id)).get();
  }

  
  // load(Object environment, String[] levels) - loads specified levels
  // delete()
  // getErrorMessages()
  // findBySignature(String)
  
  public String toString() {
    return getClass().getName()+" "+getId();
  }
  
  private Collection errors;
  
  public synchronized Collection getErrors() {
    if (errors==null) {
      try {
        errors=Collections.unmodifiableCollection(repository.getFactory().getEngine().getScanLoadError(dbData.getId(), new ArrayList()));
      } catch (SQLException e) {
        throw new MesopotamiaRuntimeException("Cannot retrieve load errors: "+e,e);
      }
    }

    return errors;
  }
  
  /**
   * Shows scan in browser. Use it for debugging.
   */
  public void show() {
    CompositeVisualizer cv = CompositeVisualizer.getThreadInstance();
    cv.addVisualizer(new MesopotamiaVisualizer());
    Visualizable v = cv.toVisualizable(this);
    
    final Object monitor = new Object();
    
    Browser browser = new Browser("Scan "+getId(), v.toTree(null)) {
      
      protected void processWindowEvent(WindowEvent e) {
        super.processWindowEvent(e);
        if (e.getID()==WindowEvent.WINDOW_CLOSED) {
          synchronized (monitor) {
            monitor.notifyAll();
          }
        }
      }
    };
    
    browser.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    browser.setVisible(true);
    
    synchronized (monitor) {
      try {
        monitor.wait();
      } catch (InterruptedException ex) {
        // Ignore
      }
    }

  }
  
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.