Package org.rascalmpl.tasks

Source Code of org.rascalmpl.tasks.Key

/*******************************************************************************
* Copyright (c) 2009-2013 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:

*   * Anya Helene Bagge - anya@ii.uib.no (Univ. Bergen)
*******************************************************************************/
package org.rascalmpl.tasks;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.eclipse.imp.pdb.facts.IAnnotatable;
import org.eclipse.imp.pdb.facts.IExternalValue;
import org.eclipse.imp.pdb.facts.ITuple;
import org.eclipse.imp.pdb.facts.IValue;
import org.eclipse.imp.pdb.facts.IWithKeywordParameters;
import org.eclipse.imp.pdb.facts.exceptions.IllegalOperationException;
import org.eclipse.imp.pdb.facts.type.ExternalType;
import org.eclipse.imp.pdb.facts.type.Type;
import org.eclipse.imp.pdb.facts.visitors.IValueVisitor;
import org.rascalmpl.interpreter.IRascalMonitor;
import org.rascalmpl.tasks.IDependencyListener.Change;
import org.rascalmpl.tasks.facts.AbstractFact;

public class Transaction  implements ITransaction<Type,IValue,IValue>, IExternalValue,
IExpirationListener<IValue> {
  public static final Type TransactionType = new ExternalType() {

    @Override
    protected Type lubWithExternal(Type type) {
      // TODO Auto-generated method stub
      return null;
    }

    @Override
    protected boolean isSubtypeOfExternal(Type type) {
      // TODO Auto-generated method stub
      return false;
    }

    @Override
    protected Type glbWithExternal(Type type) {
      // TODO Auto-generated method stub
      return null;
    }};
  private final Transaction parent;
  private final boolean commitEnabled;
  private final Map<Key, IFact<IValue>> map = new HashMap<Key, IFact<IValue>>();
  private final ITaskRegistry<Type,IValue,IValue> registry;
  private final Set<IFact<IValue>> deps = new HashSet<IFact<IValue>>();
  private final Set<Key> removed = new HashSet<Key>();
  private INameFormatter format;
  private final PrintWriter stderr;
  private Map<Type, Collection<IDependencyListener>> listeners = new HashMap<Type, Collection<IDependencyListener>>();
  public Transaction(PrintWriter stderr) {
    this(null, null, stderr, true);
  }

  public Transaction(INameFormatter format, PrintWriter stderr) {
    this(null, format, stderr, true);
  }

  public Transaction(Transaction parent, PrintWriter stderr) {
    this(parent, null, stderr, true);
  }

  public Transaction(Transaction parent, PrintWriter stderr, boolean commitEnabled) {
    this(parent, null, stderr, commitEnabled);
  }

  public Transaction(Transaction parent, INameFormatter format, PrintWriter stderr, boolean commitEnabled) {
    this.parent = parent;
    this.commitEnabled = commitEnabled;
    if(parent != null)
      this.registry = parent.registry;
    else
      this.registry = PDBValueTaskRegistry.getRegistry();
    if(format == null && parent != null)
      this.format = parent.format;
    else
      this.format = format;
    if(stderr == null)
      this.stderr = new PrintWriter(System.err);
    else
      this.stderr = stderr;
  }

  public Type getType() {
    return TransactionType;
  }

  public <T, E extends Throwable> T accept(IValueVisitor<T,E> v) throws E {
    return null;
  }

  public boolean isEqual(IValue other) {
    return false;
  }

  /*@Override
  public IValue getFact(Type key, IValue name) {
    return getFact(new NullRascalMonitor(), key, name);
  }*/
  public IValue getFact(IRascalMonitor monitor, Type key, IValue name) {
    IFact<IValue> fact = null;
    try {
      // System.err.println("GetFact: " + formatKey(key, name));
      boolean status = false;
      synchronized (this) {
        Key k = new Key(key, name);
        fact = query(k);

        if (fact != null) {
          IValue value = fact.getValue();
          if (value != null) {
            deps.add(fact);
            return value;
          }
        }
        monitor.startJob("Producing fact " + formatKey(key, name));
        Transaction tr = new Transaction(this, stderr, true);
        status = registry.produce(monitor, tr, key, name);
        monitor.endJob(true);
        fact = tr.map.get(k);
        if (fact != null) {
          tr.commit();
          deps.add(fact);
        }
        //      else
        //      tr.abandon();
      }
      if (fact != null)
        return fact.getValue();
      else {
        System.err.println("ERROR: failed to produce fact: " + formatKey(key, name)
            + "." + (status ? "" : " (producer was not authorative)"));

      }
      return null;
    }
    catch(RuntimeException t) {
      t.printStackTrace();
      throw t;
    }
  }

  public IValue queryFact(Type key, IValue name) {
    Key k = new Key(key, name);
    IFact<IValue> fact = query(k);

    if(fact != null)
      return fact.getValue();
    else
      return null;
  }

  protected IFact<IValue> query(Key k) {
    IFact<IValue> fact = map.get(k);
    if(fact == null && parent != null)
      return parent.query(k);
    else
      return fact;

  }

  public synchronized void removeFact(Type key, IValue name) {
    Key k = new Key(key, name);
    IFact<IValue> fact = map.get(k);
    map.remove(k);
    if(fact != null) {
      notifyListeners(key, fact, Change.REMOVED);
      fact.remove();
      deps.remove(fact);
      removed.add(k);
    }
  }

  public synchronized void removeFact(IFact<IValue> fact) {
    removeFact(((Key)fact.getKey()).type, ((Key)fact.getKey()).name);
  }

  public synchronized IFact<IValue> setFact(Type key, IValue name, IValue value) {
    return setFact(key, name, value, null, FactFactory.getInstance());
  }

  public synchronized IFact<IValue> setFact(Type key, IValue name, IValue value,
      Collection<IFact<IValue>> dependencies) {
    return setFact(key, name, value, dependencies, FactFactory.getInstance());
  }

  @Override
  public synchronized IFact<IValue> setFact(Type key, IValue name, IFact<IValue> fact) {
    Key k = new Key(key, name);
    IFact<IValue> oldFact = map.get(k);

    if(oldFact == null) {
      map.put(k, fact);
      removed.remove(k);
    }
    else if(oldFact != fact) {
      oldFact.remove();
      map.put(k, fact);
      removed.remove(k);
    }

    notifyListeners(key, fact, Change.CHANGED);

    return fact;
  }

  public synchronized IFact<IValue> setFact(Type key, IValue name, IValue value,
      Collection<IFact<IValue>> dependencies, IFactFactory factory) {
    Key k = new Key(key, name);
    IFact<IValue> fact = map.get(k);
    if(fact == null) {
      fact = factory.fact(IValue.class, k, formatKey(k), this, registry.getDepPolicy(key), registry.getRefPolicy(key));
    }
    boolean change = fact.setValue(value);
    if(dependencies != null)
      fact.setDepends(Collections.unmodifiableCollection(dependencies));
    else
      fact.setDepends(Collections.unmodifiableCollection(deps));
    map.put(k, fact);
    removed.remove(k);

    if(change)
      notifyListeners(key, fact, Change.CHANGED);
    /*AVOID CONSOLE PRINTING WITHIN SYNCHRONIZED?
     * stderr.printf("Set fact %s = %s\n    <- ", formatKey(key, name), abbrev(value.toString(), 40));
    for(IFact<?> d : fact.getDepends())
      stderr.print(formatKey(d.getKey()) + " ");
    stderr.println();
    stderr.flush();
     */

    return fact;
  }

  // Remove?
//  private String abbrev(String s, int len) {
//    if(s.length() > len)
//      s = s.substring(0, len) + "...";
//    return s;
//  }

  public void abandon() {
    for(IFact<IValue> fact : map.values()) {
      notifyListeners(((Key)fact.getKey()).type, fact, Change.REMOVED);
      fact.remove(); // TODO: dispose?
    }
    map.clear();
    removed.clear();
    deps.clear();
  }

  public void commit() {
    if(parent != null && commitEnabled) {
      if(parent.parent == null) {
        AbstractFact.pruneExpired();
      }
      for(Key k : removed) {
        parent.removeFact(k.type, k.name);
      }
      Set<IDependencyListener> toNotify = new HashSet<IDependencyListener>();
      Set<IDependencyListener> trSet= new HashSet<IDependencyListener>();

      for(Key k : map.keySet()) {
        IFact<IValue> fact = parent.map.get(k);
        IFact<IValue> trFact = map.get(k);
        trSet.add(trFact);
        if(fact != null) {
          Collection<IDependencyListener> ls = fact.getListeners();
          if(fact.updateFrom(trFact)) {
            parent.notifyListeners(k.type, fact, Change.CHANGED);
            toNotify.addAll(ls);
          }
          trSet.add(fact);
        }
        else {
          parent.map.put(k, map.get(k));
          parent.notifyListeners(k.type, trFact, Change.CHANGED);
        }
      }
      // TODO: update fact references
    }
  }

  public void commit(Collection<IFact<IValue>> deps) {
    if(parent != null && commitEnabled) {
      for(Key k : removed) {
        parent.removeFact(k.type, k.name);
      }
      for(Key k : map.keySet()) {
        IFact<IValue> fact = parent.query(k);
        map.get(k).setDepends(deps);
        if(fact != null) {
          if(fact.updateFrom(map.get(k)))
            parent.notifyListeners(k.type, fact, Change.CHANGED);
        }
        else {
          parent.map.put(k, map.get(k));
          parent.notifyListeners(k.type, map.get(k), Change.CHANGED);
        }
      }
    }
  }

  private void notifyListeners(Type k, IFact<IValue> fact, Change change) {
    Collection<IDependencyListener> ls = listeners.get(k);
    if(ls != null)
      for(IDependencyListener l : ls) {
        l.changed(fact, change, null);
      }
  }

  public synchronized void registerListener(IDependencyListener listener, Type key) {
    Collection<IDependencyListener> ls = listeners.get(key);
    if(ls == null)
      ls = new ArrayList<IDependencyListener>();
    if(!ls.contains(listener))
      ls.add(listener);
    listeners.put(key, ls);
  }

  public synchronized void unregisterListener(IDependencyListener listener, Type key) {
    Collection<IDependencyListener> ls = listeners.get(key);
    if(ls != null) {
      ls.remove(listener);
      listeners.put(key, ls);
    }
  }

  private String formatKey(Object key) {
    if(key instanceof Key) {
      Key k = (Key)key;
      return formatKey(k.type, k.name);
    }
    else
      return key.toString();
  }

  private String formatKey(Type key, IValue name) {
    String n;
    if(format == null && parent != null)
      return parent.formatKey(key, name);
    else if(format != null)
      n = format.format(name);
    else
      n = name.toString();

    return key.getName() + "(" + n + ")";
  }

  public IFact<IValue> findFact(Type key, IValue name) {
    return query(new Key(key, name));
  }

  public static Key makeKey(Type key, IValue name) {
    return new Key(key, name);
  }

  public ITuple getGraph() {
    GraphBuilder g = new GraphBuilder();
    for(Key k : map.keySet()) {
      g.addFact(map.get(k), k.type.getName(), map.get(k).getStatus());     
    }
    for(IFact<?> fact : map.values()) {
      for(IFact<?> d : fact.getDepends()) {
        if(d.getListeners().contains(fact))
          g.arrow(fact, d, "<->");
        else {
          g.arrow(fact, d, "->");
          System.err.printf("Warning: fact %s depends on %s but does not listen on it.", fact, d);
        }
      }
    }
    return g.getGraph();
  }

  public synchronized void expire(Object key) {
    Key k = (Key) key;
    map.remove(k);
    removed.add(k);
  }

  @Override
  public boolean isAnnotatable() {
    return false;
  }

  @Override
  public IAnnotatable<? extends IValue> asAnnotatable() {
    throw new IllegalOperationException(
        "Cannot be viewed as annotatable.", getType());
  }
 
   @Override
   public boolean mayHaveKeywordParameters() {
     return false;
   }
  
   @Override
   public IWithKeywordParameters<? extends IValue> asWithKeywordParameters() {
     throw new IllegalOperationException(
         "Cannot be viewed as with keyword parameters", getType());
   }
}

class Key {
  public final Type type;
  public final IValue name;

  Key(Type type, IValue name) {
    this.type = type;
    this.name = name;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    result = prime * result + ((type == null) ? 0 : type.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    Key other = (Key) obj;
    if (name == null) {
      if (other.name != null)
        return false;
    } else if (!name.isEqual(other.name))
      return false;
    if (type == null) {
      if (other.type != null)
        return false;
    } else if (!type.equals(other.type))
      return false;
    return true;
  }
}
TOP

Related Classes of org.rascalmpl.tasks.Key

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.