| // Copyright (C) 2011 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.google.gerrit.rules; |
| |
| import com.google.inject.Inject; |
| import com.google.inject.Injector; |
| import com.google.inject.assistedinject.Assisted; |
| |
| import com.googlecode.prolog_cafe.lang.BufferingPrologControl; |
| import com.googlecode.prolog_cafe.lang.Prolog; |
| import com.googlecode.prolog_cafe.lang.PrologMachineCopy; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.util.EnumSet; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * Per-thread Prolog interpreter. |
| * <p> |
| * This class is not thread safe. |
| * <p> |
| * A single copy of the Prolog interpreter, for the current thread. |
| */ |
| public class PrologEnvironment extends BufferingPrologControl { |
| |
| private static final Logger log = |
| LoggerFactory.getLogger(PrologEnvironment.class); |
| |
| static final int MAX_ARITY = 8; |
| |
| public static interface Factory { |
| /** |
| * Construct a new Prolog interpreter. |
| * |
| * @param src the machine to template the new environment from. |
| * @return the new interpreter. |
| */ |
| PrologEnvironment create(PrologMachineCopy src); |
| } |
| |
| private final Injector injector; |
| private final Map<StoredValue<Object>, Object> storedValues; |
| private List<Runnable> cleanup; |
| |
| @Inject |
| PrologEnvironment(Injector i, @Assisted PrologMachineCopy src) { |
| super(src); |
| injector = i; |
| setMaxArity(MAX_ARITY); |
| setEnabled(EnumSet.allOf(Prolog.Feature.class), false); |
| storedValues = new HashMap<StoredValue<Object>, Object>(); |
| cleanup = new LinkedList<Runnable>(); |
| } |
| |
| /** Get the global Guice Injector that configured the environment. */ |
| public Injector getInjector() { |
| return injector; |
| } |
| |
| /** |
| * Lookup a stored value in the interpreter's hash manager. |
| * |
| * @param <T> type of stored Java object. |
| * @param sv unique key. |
| * @return the value; null if not stored. |
| */ |
| @SuppressWarnings("unchecked") |
| public <T> T get(StoredValue<T> sv) { |
| return (T) storedValues.get(sv); |
| } |
| |
| /** |
| * Set a stored value on the interpreter's hash manager. |
| * |
| * @param <T> type of stored Java object. |
| * @param sv unique key. |
| * @param obj the value to store under {@code sv}. |
| */ |
| @SuppressWarnings("unchecked") |
| public <T> void set(StoredValue<T> sv, T obj) { |
| storedValues.put((StoredValue<Object>) sv, obj); |
| } |
| |
| /** |
| * Copy the stored values from another interpreter to this one. |
| * Also gets the cleanup from the child interpreter |
| */ |
| public void copyStoredValues(PrologEnvironment child) { |
| storedValues.putAll(child.storedValues); |
| setCleanup(child.cleanup); |
| } |
| |
| /** |
| * Assign the environment a cleanup list (in order to use a centralized list) |
| * If this enivronment's list is non-empty, append its cleanup tasks to the |
| * assigning list. |
| */ |
| public void setCleanup(List<Runnable> newCleanupList) { |
| newCleanupList.addAll(cleanup); |
| cleanup = newCleanupList; |
| } |
| |
| /** |
| * Adds cleanup task to run when close() is called |
| * @param task is run when close() is called |
| */ |
| public void addToCleanup(Runnable task) { |
| cleanup.add(task); |
| } |
| |
| /** |
| * Release resources stored in interpreter's hash manager. |
| */ |
| public void close() { |
| for (final Iterator<Runnable> i = cleanup.iterator(); i.hasNext();) { |
| try { |
| i.next().run(); |
| } catch (Throwable err) { |
| log.error("Failed to execute cleanup for PrologEnvironment", err); |
| } |
| i.remove(); |
| } |
| } |
| } |