All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.googlecode.sarasvati.load.GraphLoaderImpl Maven / Gradle / Ivy

The newest version!
/*
    This file is part of Sarasvati.

    Sarasvati 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 3 of the
    License, or (at your option) any later version.

    Sarasvati 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 Sarasvati.  If not, see .

    Copyright 2008-2009 Paul Lorenz
                        Vincent Kirsch
*/

package com.googlecode.sarasvati.load;

import java.io.File;
import java.io.FilenameFilter;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import com.googlecode.sarasvati.Graph;
import com.googlecode.sarasvati.load.definition.ExternalDefinition;
import com.googlecode.sarasvati.load.definition.ProcessDefinition;
import com.googlecode.sarasvati.util.FileVisitor;
import com.googlecode.sarasvati.util.SvUtil;
import com.googlecode.sarasvati.xml.XmlLoader;
import com.googlecode.sarasvati.xml.XmlProcessDefinition;

/**
 * Given a {@link GraphFactory} to construct the {@link Graph} parts,
 * a {@link GraphRepository} and a {@link ProcessDefinitionTranslator} to translate the
 * "raw" definition (for example an XML file) into a ProcessDefinition it can understand,
 * the GraphLoader will load process definitions into that repository.
 *
 * This class is *not* thread safe
 *
 * @author Paul Lorenz
 */
public class GraphLoaderImpl extends AbstractGraphLoader
{
  public GraphLoaderImpl (final GraphFactory factory,
                          final GraphRepository repository,
                          final GraphValidator validator)
  {
    super( factory, repository, validator );
  }

  @Override
  public  void loadDefinition (final ProcessDefinitionTranslator translator, final T source)
    throws SarasvatiLoadException
  {
    loadDefinition( translator.translate( source ) );
  }

  @Override
  public  void loadDefinition (final ProcessDefinitionTranslator translator,
                                  final T source,
                                  final String customId)
    throws SarasvatiLoadException
  {
    loadDefinition( translator.translate( source ), customId );
  }

  @Override
  public void loadDefinition (final ProcessDefinition procDef)
    throws SarasvatiLoadException
  {
    loadDefinition( procDef, procDef.getMessageDigest() );
  }

  @Override
  public List loadWithDependencies (final String name, final ProcessDefinitionResolver resolver)
    throws SarasvatiLoadException
  {
    ProcessDefinition procDef = resolver.resolve( name );
    List results = loadDependenciesIfNeeded( procDef, resolver, new Stack(), new HashMap() );
    LoadResult result = loadIfNeeded( procDef, results );
    if ( result != null )
    {
      results.add( result );
    }
    return results;
  }

  private List loadDependenciesIfNeeded (final ProcessDefinition procDef,
                                                     final ProcessDefinitionResolver resolver,
                                                     final Stack stack,
                                                     final Map loaded)
  {
    List results = new LinkedList();
    stack.push( procDef.getName() );

    for ( ExternalDefinition external : procDef.getExternals() )
    {
      String extName = external.getProcessDefinition();
      if ( stack.contains( extName ) )
      {
        throw new SarasvatiLoadException( "Process definition '" + procDef.getName() +
                                          "' contains an illegal recursive reference to '" +
                                          extName + "'" );
      }

      ProcessDefinition externalDef = loaded.get( extName );
      if ( externalDef == null )
      {
        externalDef = resolver.resolve( extName );
        loaded.put( extName, externalDef );
      }

      List childResults = loadDependenciesIfNeeded( externalDef, resolver, stack, loaded );
      results.addAll( childResults );
      LoadResult result = loadIfNeeded( externalDef, childResults );
      if ( result != null )
      {
        results.add( result );
      }
    }

    stack.pop();
    return results;
  }

  private LoadResult loadIfNeeded (final ProcessDefinition procDef,
                                   final List childResults )
  {
    Graph latest = repository.getLatestGraph( procDef.getName() );
    String digest = procDef.getMessageDigest();

    if ( latest == null )
    {
      loadDefinition( procDef );
      return LoadResult.newGraph( procDef.getName() );
    }

    if ( !digest.equals( latest.getCustomId() ) )
    {
      loadDefinition( procDef );
      return LoadResult.updatedGraph( procDef.getName() );
    }
    else if ( !childResults.isEmpty() )
    {
      loadDefinition( procDef );
      return LoadResult.updatedGraph( procDef.getName(), childResults.get( 0 ).getName() );
    }
    return null;
  }

  @Override
  public boolean isLoaded (final String name)
  {
    return null != repository.getLatestGraph( name );
  }

  @Override
  public List loadNewAndChanged (final File basePath)
    throws SarasvatiLoadException
  {
    return loadNewAndChanged( basePath, null );
  }

  @Override
  public List loadNewAndChanged (final File basePath,
                                             final FilenameFilter filenameFilter)
    throws SarasvatiLoadException
  {
    final XmlLoader xmlLoader = new XmlLoader();
    final Map processDefs = new HashMap();

    final FilenameFilter filter =
      filenameFilter != null ?
          filenameFilter :
          new FilenameFilter()
          {
            @Override
            public boolean accept (final File dir, final String name)
            {
              return name.endsWith( ".wf.xml" );
            }
          };

    FileVisitor visitor = new FileVisitor()
    {
      @Override
      public boolean accept (final File dir, final String name)
      {
        return filter.accept( dir, name );
      }

      @Override
      public void accept (final File file)
      {
        XmlProcessDefinition pd = xmlLoader.translate( file );
        processDefs.put( pd.getName(), pd );
      }
    };

    Set updated = new HashSet();

    SvUtil.visitRecursive( basePath, visitor, true );

    List loadResults = new LinkedList();

    // Find all process definitions that are new or have changed
    for ( ProcessDefinition processDefinition : processDefs.values() )
    {
      String name   = processDefinition.getName();
      String digest = processDefinition.getMessageDigest();

      Graph latest = repository.getLatestGraph( name );
      if ( latest == null )
      {
        updated.add( name );
        loadResults.add( LoadResult.newGraph( name ) );
      }
      else if ( !digest.equals( latest.getCustomId() ) )
      {
        updated.add( name );
        loadResults.add( LoadResult.updatedGraph( name ) );
      }
    }

    // Collection is sorted so that externals are before all places that they are used.
    Collection sorted = SvUtil.getSorted( processDefs );

    // Find all process definition which depend on those that have been updated
    for ( ProcessDefinition processDefinition : sorted )
    {
      String name = processDefinition.getName();
      // If we already know it needs to updated, skip checking this one
      if ( updated.contains( name ) )
      {
        continue;
      }

      for ( ExternalDefinition ext : processDefinition.getExternals() )
      {
        if ( updated.contains( ext.getProcessDefinition() ) )
        {
          updated.add( name );
          loadResults.add( LoadResult.updatedGraph( name, ext.getProcessDefinition() ) );
          break;
        }
      }
    }

    // Load all updated/new process definitions in order
    for ( ProcessDefinition processDefinition : sorted )
    {
      if ( updated.contains( processDefinition.getName() ) )
      {
        loadDefinition( processDefinition, processDefinition.getMessageDigest() );
      }
    }

    return loadResults;
  }

  /**
   * Loads the given XML process definition file.
   *
   * @param file The xml file to load
   */
  @Override
  public void load (final File file)
  {
    loadDefinition( new XmlLoader(), file );
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy