edu.cmu.lti.oaqa.cse.space.uima.list.ExperimentBuilder.java Source code

Java tutorial

Introduction

Here is the source code for edu.cmu.lti.oaqa.cse.space.uima.list.ExperimentBuilder.java

Source

/*
 *  Copyright 2012 Carnegie Mellon University
 *
 *  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 edu.cmu.lti.oaqa.cse.space.uima.list;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nullable;

import mx.bigdata.anyobject.AnyObject;
import mx.bigdata.anyobject.AnyTuple;

import org.apache.uima.UIMAFramework;
import org.apache.uima.UimaContext;
import org.apache.uima.UimaContextAdmin;
import org.apache.uima.analysis_component.AnalysisComponent;
import org.apache.uima.analysis_component.JCasAnnotator_ImplBase;
import org.apache.uima.analysis_engine.AnalysisEngine;
import org.apache.uima.analysis_engine.AnalysisEngineDescription;
import org.apache.uima.analysis_engine.metadata.FixedFlow;
import org.apache.uima.collection.CollectionReader;
import org.apache.uima.flow.FlowControllerDescription;
import org.apache.uima.resource.CustomResourceSpecifier;
import org.apache.uima.resource.Resource;
import org.apache.uima.resource.ResourceInitializationException;
import org.apache.uima.resource.impl.CustomResourceSpecifier_impl;
import org.apache.uima.resource.metadata.TypePriorities;
import org.apache.uima.resource.metadata.TypeSystemDescription;
import org.uimafit.factory.AggregateBuilder;
import org.uimafit.factory.AnalysisEngineFactory;
import org.uimafit.factory.CollectionReaderFactory;
import org.uimafit.factory.FlowControllerFactory;
import org.uimafit.factory.TypePrioritiesFactory;
import org.yaml.snakeyaml.Yaml;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import edu.cmu.lti.oaqa.cse.ResourceHandle;
import edu.cmu.lti.oaqa.cse.ResourceHandle.HandleType;
import edu.cmu.lti.oaqa.cse.configuration.CollectionReaderDescriptor;
import edu.cmu.lti.oaqa.cse.configuration.ComponentDescriptor;
import edu.cmu.lti.oaqa.cse.configuration.Parameter;
import edu.cmu.lti.oaqa.ecd.config.ConfigurationLoader;
import edu.cmu.lti.oaqa.ecd.flow.FixedFlowController797182;
import edu.cmu.lti.oaqa.ecd.impl.AbstractExperimentPersistenceProvider;
import edu.cmu.lti.oaqa.ecd.impl.DefaultExperimentPersistenceProvider;

public class ExperimentBuilder {

    private static final Set<String> FILTER = ImmutableSet.of("class", "inherit", "pipeline");

    private static final ResourceHandle NOOP_RESOURCE = ResourceHandle.newInheritHandle("base.noop");

    public static final String EXPERIMENT_UUID_PROPERTY = "cse.driver.experiment.uuid";

    public static final String STAGE_ID_PROPERTY = "cse.driver.experiment.stageIdd";

    private final TypeSystemDescription typeSystem;

    private final String experimentUuid;

    //   private final AnyObject configuration;

    //   private final AbstractExperimentPersistenceProvider persistence;

    private TypePriorities typePriorities = (TypePriorities) null;

    public ExperimentBuilder(String experimentUuid, String resource, TypeSystemDescription typeSystem)
            throws Exception {
        this.typeSystem = typeSystem;
        this.experimentUuid = experimentUuid;
        //this.configuration = ConfigurationLoader.load(resource);
        //this.persistence = newPersistenceProvider(configuration);
        //insertExperiment(configuration, resource);
    }

    public String getExperimentUuid() {
        return experimentUuid;
    }

    public AnalysisEngine createNoOpEngine() throws Exception {
        Map<String, Object> tuples = Maps.newLinkedHashMap();
        Class<? extends AnalysisComponent> ac = loadFromClassOrInherit(NOOP_RESOURCE, AnalysisComponent.class,
                tuples);
        AnalysisEngineDescription aeDesc = createAnalysisEngineDescription(tuples, ac);
        System.out.println("\t- " + aeDesc.getAnalysisEngineMetaData().getName());
        return produceAnalysisEngine(null, aeDesc);
    }

    //   public AnalysisEngine buildPipeline(AnyObject config, String pipeline,
    //         int stageId, FixedFlow funnel) throws Exception {
    //      try {
    //         return buildPipeline(config, pipeline, stageId, funnel, false);
    //      } catch (Exception e) {
    //         Throwables.propagateIfInstanceOf(e,
    //               ResourceInitializationException.class);
    //         throw new ResourceInitializationException(
    //               ResourceInitializationException.ERROR_INITIALIZING_FROM_DESCRIPTOR,
    //               new Object[] { pipeline, config }, e);
    //      }
    //   }

    //   public AnalysisEngine buildPipeline(AnyObject config, String pipeline,
    //         int stageId, FixedFlow funnel, boolean outputNewCASes)
    //         throws Exception {
    //      loadTypePriorities(config);
    //      Iterable<AnyObject> iterable = config.getIterable(pipeline);
    //      FlowControllerDescription fcd = FlowControllerFactory
    //            .createFlowControllerDescription(FixedFlowController797182.class);
    //      AnalysisEngineDescription aee = buildPipeline(stageId, iterable, fcd);
    //      if (funnel != null) {
    //         FixedFlow fc = (FixedFlow) aee.getAnalysisEngineMetaData()
    //               .getFlowConstraints();
    //         funnel.setFixedFlow(fc.getFixedFlow());
    //         aee.getAnalysisEngineMetaData().setFlowConstraints(funnel);
    //      }
    //      aee.getAnalysisEngineMetaData().getOperationalProperties()
    //            .setOutputsNewCASes(outputNewCASes);
    //      aee.getAnalysisEngineMetaData().setName(pipeline);
    //      return AnalysisEngineFactory.createAggregate(aee);
    //   }

    //   public AnalysisEngine buildPipeline(AnyObject config, String pipeline,
    //         int stageId) throws Exception {
    //      try {
    //         return buildPipeline(config, pipeline, stageId, null, false);
    //      } catch (Exception e) {
    //         throw new ResourceInitializationException(
    //               ResourceInitializationException.ERROR_INITIALIZING_FROM_DESCRIPTOR,
    //               new Object[] { pipeline, config }, e);
    //      }
    //   }

    //   private AnalysisEngineDescription buildPipeline(int stageId,
    //         Iterable<AnyObject> pipeline, FlowControllerDescription fcd)
    //         throws Exception {
    //      AggregateBuilder builder = new AggregateBuilder(null, null, fcd);
    //      int phase = 1;
    //      for (AnyObject aeDescription : pipeline) {
    //         AnalysisEngineDescription description = buildComponent(stageId,
    //               phase, aeDescription);
    //         builder.add(description);
    //         phase++;
    //      }
    //      return builder.createAggregateDescription();
    //   }

    private String[] getFromListOrInherit(AnyObject descriptor, String listName) throws IOException {
        Iterable<String> iterable = descriptor.getIterable(listName);
        if (iterable != null) {
            ArrayList<String> typePrioritiesList = new ArrayList<String>();
            for (String type : iterable) {
                typePrioritiesList.add(type);
                System.out.println("Loaded type priorities: " + type);
            }
            return typePrioritiesList.toArray(new String[0]);
        } else {
            String resource = descriptor.getString("inherit");
            if (resource != null) {
                AnyObject yaml = ConfigurationLoader.load(resource);
                return getFromListOrInherit(yaml, listName);
            } else {
                throw new IllegalArgumentException("Illegal experiment descriptor, must contain one list of type <"
                        + listName + "> or <inherit>");
            }
        }
    }

    // Load type priorities
    private void loadTypePriorities(AnyObject config) {
        AnyObject tpObject = config.getAnyObject("type-priorities");
        if (tpObject == null) {
            return;
        }
        try {
            String[] typePrioritiesArray = getFromListOrInherit(tpObject, "type-list");
            this.typePriorities = TypePrioritiesFactory.createTypePriorities(typePrioritiesArray);
        } catch (IOException e) {
            System.err.println("Failed to load type-priorities.");
            e.printStackTrace();
        }
    }

    // Made this method public to invoke it from BasePhaseTest
    public AnalysisEngineDescription buildComponent(ComponentDescriptor descriptor) throws Exception {
        Map<String, Object> tuples = Maps.newLinkedHashMap();
        tuples.put(EXPERIMENT_UUID_PROPERTY, experimentUuid);
        Class<? extends AnalysisComponent> ac = Class.forName(descriptor.getClassName())
                .asSubclass(AnalysisComponent.class);
        Map<String, Parameter> parameters = descriptor.getParamMap();
        Object[] params = getParamArray(parameters);
        AnalysisEngineDescription description = AnalysisEngineFactory.createPrimitiveDescription(ac, typeSystem,
                typePriorities, params);
        String name = (String) tuples.get("name");
        description.getAnalysisEngineMetaData().setName(name);
        return description;
    }

    public CollectionReader buildCollectionReader(CollectionReaderDescriptor descriptor) throws Exception {
        Map<String, Object> tuples = Maps.newLinkedHashMap();
        tuples.put(EXPERIMENT_UUID_PROPERTY, experimentUuid);
        Class<? extends CollectionReader> readerClass = Class.forName(descriptor.getClassName())
                .asSubclass(CollectionReader.class);
        Map<String, Parameter> parameters = descriptor.getParamMap();
        Object[] params = getParamArray(parameters);
        CollectionReader reader = CollectionReaderFactory.createCollectionReader(readerClass, typeSystem, params);
        return reader;
    }

    public <T extends Resource> T initializeResource(AnyObject config, String node, Class<T> type)
            throws Exception {
        AnyObject descriptor = config.getAnyObject(node);
        if (descriptor == null) {
            return null;
        }
        Map<String, Object> tuples = Maps.newLinkedHashMap();
        Class<? extends Resource> cseClass = getFromClassOrInherit(descriptor, Resource.class, tuples);
        return buildResource(cseClass, tuples, type);
    }

    //   private void insertExperiment(AnyObject config, String resource)
    //         throws Exception {
    //      AnyObject experiment = config.getAnyObject("configuration");
    //      String name = experiment.getString("name");
    //      String author = experiment.getString("author");
    //      persistence.insertExperiment(getExperimentUuid(), name, author,
    //            ConfigurationLoader.getString(resource), resource);
    //   }

    public static <T extends Resource> T loadProvider(String provider, Class<T> type)
            throws ResourceInitializationException {
        Yaml yaml = new Yaml();
        @SuppressWarnings("unchecked")
        Map<String, String> map = (Map<String, String>) yaml.load(provider);
        ResourceHandle handle = buildHandleFromMap(map);
        try {
            return buildResource(handle, type);
        } catch (Exception e) {
            throw new ResourceInitializationException(
                    ResourceInitializationException.ERROR_INITIALIZING_FROM_DESCRIPTOR,
                    new Object[] { type.getCanonicalName(), provider }, e);
        }
    }

    public static <T extends Resource> T loadProvider(AnyObject ao, Class<T> type)
            throws ResourceInitializationException {
        ResourceHandle handle = buildHandleFromObject(ao);
        try {
            return buildResource(handle, type);
        } catch (Exception e) {
            throw new ResourceInitializationException(
                    ResourceInitializationException.ERROR_INITIALIZING_FROM_DESCRIPTOR,
                    new Object[] { type.getCanonicalName(), ao }, e);
        }
    }

    public static AnalysisEngine[] createAnnotators(String description) {
        Yaml yaml = new Yaml();
        @SuppressWarnings("unchecked")
        List<Map<String, String>> names = (List<Map<String, String>>) yaml.load(description);
        List<AnalysisEngine> annotators = Lists.newArrayList();
        for (Map<String, String> name : names) {
            try {
                Map<String, Object> tuples = Maps.newHashMap();
                ResourceHandle handle = buildHandleFromMap(name);
                Class<? extends JCasAnnotator_ImplBase> aClass = loadFromClassOrInherit(handle,
                        JCasAnnotator_ImplBase.class, tuples);
                Object[] params = getParamList(tuples);
                AnalysisEngineDescription aeDesc = AnalysisEngineFactory.createPrimitiveDescription(aClass, params);
                annotators.add(UIMAFramework.produceAnalysisEngine(aeDesc));
            } catch (Exception e) {
                System.err.printf("[ERROR] %s Caused by:\n", e);
                Throwables.getRootCause(e).printStackTrace();
            }
        }
        return annotators.toArray(new AnalysisEngine[0]);
    }

    public static <T extends Resource> List<T> createResourceList(List<Map<String, String>> names, Class<T> type) {
        List<T> resources = Lists.newArrayList();
        for (Map<String, String> name : names) {
            try {
                ResourceHandle handle = buildHandleFromMap(name);
                resources.add(buildResource(handle, type));
            } catch (Exception e) {
                System.err.printf("[ERROR] %s Caused by:\n", e);
                Throwables.getRootCause(e).printStackTrace();
            }
        }
        return resources;
    }

    public static <T extends Resource> T buildResource(ResourceHandle handle, Class<T> type)
            throws ResourceInitializationException {
        Map<String, Object> tuples = Maps.newLinkedHashMap();
        try {
            Class<? extends Resource> resourceClass = loadFromClassOrInherit(handle, Resource.class, tuples);
            return buildResource(resourceClass, tuples, type);
        } catch (Exception e) {
            throw new ResourceInitializationException(
                    ResourceInitializationException.ERROR_INITIALIZING_FROM_DESCRIPTOR,
                    new Object[] { type.getCanonicalName(), handle }, e);
        }
    }

    private static <T extends Resource> T buildResource(Class<? extends Resource> resourceClass,
            Map<String, Object> tuples, Class<T> type) throws Exception {
        CustomResourceSpecifier spec = new CustomResourceSpecifier_impl();
        spec.setResourceClassName(resourceClass.getName());
        Resource resource = UIMAFramework.produceResource(spec, tuples);
        return type.cast(resource);
    }

    public static Object[] getParamList(Map<String, Object> tuples) {
        List<Object> params = Lists.newArrayList();
        for (Map.Entry<String, Object> me : tuples.entrySet()) {
            params.add(me.getKey());
            params.add(cast(me.getValue()));
        }
        return params.toArray();
    }

    public static Object[] getParamArray(Map<String, Parameter> tuples) {
        List<Object> params = Lists.newArrayList();
        for (Map.Entry<String, Parameter> me : tuples.entrySet()) {
            params.add(me.getKey());
            params.add(cast(me.getValue().getVal()));
        }
        return params.toArray();
    }

    private static Object cast(Object o) {
        if (o instanceof Iterable) {
            List<?> list = Lists.newArrayList((Iterable<?>) o);
            Object k = list.get(0);
            if (k instanceof String) {
                return list.toArray(new String[0]);
            } else if (k instanceof Integer) {
                return list.toArray(new Integer[0]);
            } else if (k instanceof Float) {
                return list.toArray(new Float[0]);
            } else if (k instanceof Double) {
                List<Float> bogus = Lists.newArrayList();
                for (Object j : list) {
                    bogus.add(((Double) j).floatValue());
                }
                return bogus.toArray(new Float[0]);
            } else if (list.get(0) instanceof Boolean) {
                return list.toArray(new Boolean[0]);
            }
        } else if (o instanceof Double) {
            return ((Double) o).floatValue();
        }
        return o;
    }

    public static <C> Class<? extends C> getFromClassOrInherit(AnyObject descriptor, Class<C> ifaceClass,
            Map<String, Object> tuples) throws Exception {
        for (AnyTuple tuple : descriptor.getTuples()) {
            if (!FILTER.contains(tuple.getKey())) {
                if (!tuples.containsKey(tuple.getKey())) {
                    tuples.put(tuple.getKey(), tuple.getObject());
                }
            }
        }
        String name = descriptor.getString("class");
        if (name != null) {
            return Class.forName(name).asSubclass(ifaceClass);
        } else {
            String resource = descriptor.getString("inherit");
            if (resource != null) {
                AnyObject yaml = ConfigurationLoader.load(resource);
                return getFromClassOrInherit(yaml, ifaceClass, tuples);
            } else {
                throw new IllegalArgumentException(
                        "Illegal experiment descriptor, must contain one node of type <class> or <inherit>");
            }
        }
    }

    public static <C> Class<? extends C> loadFromClassOrInherit(ResourceHandle resource, Class<C> ifaceClass,
            Map<String, Object> tuples) throws Exception {
        if (resource.getType() == HandleType.CLASS) {
            return Class.forName(resource.resource).asSubclass(ifaceClass);
        } else {
            if (resource.getType() == HandleType.INHERIT) {
                AnyObject yaml = ConfigurationLoader.load(resource.resource);
                return getFromClassOrInherit(yaml, ifaceClass, tuples);
            } else {
                throw new IllegalArgumentException(
                        "Illegal experiment descriptor, must contain one node of type <class> or <inherit>");
            }
        }
    }

    public static AnalysisEngineDescription createAnalysisEngineDescription(Map<String, Object> tuples,
            Class<? extends AnalysisComponent> comp) throws ResourceInitializationException {
        Object[] params = getParamList(tuples);
        AnalysisEngineDescription aeDesc = AnalysisEngineFactory.createPrimitiveDescription(comp, params);
        StringBuilder sb = new StringBuilder(comp.getSimpleName());
        if (params.length > 0) {
            appendMethodSignature(sb, tuples);
        }
        String name = sb.toString().replaceAll("\n", " ").trim();
        aeDesc.getAnalysisEngineMetaData().setName(name);
        return aeDesc;

    }

    public static AnalysisEngine produceAnalysisEngine(@Nullable UimaContext c, AnalysisEngineDescription aeDesc)
            throws ResourceInitializationException {
        AnalysisEngine ae;
        if (c != null) {
            ae = UIMAFramework.produceAnalysisEngine(aeDesc, ((UimaContextAdmin) c).getResourceManager(), null);
        } else {
            ae = UIMAFramework.produceAnalysisEngine(aeDesc);
        }
        return ae;
    }

    public static <T> T createFromName(String name, Class<T> type)
            throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        Class<? extends T> clazz = Class.forName(name).asSubclass(type);
        return clazz.newInstance();
    }

    private static ResourceHandle buildHandleFromString(String name) {
        String[] values = name.split("!");
        return ResourceHandle.newHandle(values[0], values[1]);
    }

    public static ResourceHandle buildHandleFromMap(Map<String, String> map) {
        Map.Entry<String, String> name = Iterators.get(map.entrySet().iterator(), 0);
        return ResourceHandle.newHandle(name.getKey(), name.getValue());
    }

    public static ResourceHandle buildHandleFromObject(AnyObject object) {
        AnyTuple name = Iterables.get(object.getTuples(), 0);
        return ResourceHandle.newHandle(name.getKey(), (String) name.getObject());
    }

    private static void appendMethodSignature(StringBuilder sb, Map<String, Object> tuples) {
        Map<String, String> ftuples = Maps.transformValues(tuples, new ObjectFormatter());
        sb.append("[");
        Joiner.MapJoiner joiner = Joiner.on("#").withKeyValueSeparator(":");
        joiner.appendTo(sb, ftuples);
        sb.append("]");
    }

    private final static class ObjectFormatter implements Function<Object, String> {

        @Override
        public String apply(Object o) {
            if (o instanceof Iterable) {
                Joiner joiner = Joiner.on("#");
                return joiner.join((Iterable<?>) o).toString();
            }
            return o.toString();
        }

    }

    // These methods are preserved for compatibility with the old version of
    // PhaseImpl

    @Deprecated
    public static <C> Class<? extends C> loadFromClassOrInherit(String handle, Class<C> ifaceClass,
            Map<String, Object> tuples) throws Exception {
        String[] name = handle.split("!");
        if (name[0].equals("class")) {
            return Class.forName(name[1]).asSubclass(ifaceClass);
        } else {
            if (name[0].equals("inherit")) {
                AnyObject yaml = ConfigurationLoader.load(name[1]);
                return getFromClassOrInherit(yaml, ifaceClass, tuples);
            } else {
                throw new IllegalArgumentException(
                        "Illegal experiment descriptor, must contain one node of type <class> or <inherit>");
            }
        }
    }

    @Deprecated
    public static AnalysisEngine createAnalysisEngine(@Nullable UimaContext c, Map<String, Object> tuples,
            Class<? extends AnalysisComponent> comp) throws ResourceInitializationException {
        Object[] params = getParamList(tuples);
        AnalysisEngineDescription aeDesc = AnalysisEngineFactory.createPrimitiveDescription(comp, params);
        StringBuilder sb = new StringBuilder(comp.getSimpleName());
        if (params.length > 0) {
            appendMethodSignature(sb, tuples);
        }
        aeDesc.getAnalysisEngineMetaData().setName(sb.toString());
        System.out.println("\t- " + sb.toString());
        AnalysisEngine ae;
        if (c != null) {
            ae = UIMAFramework.produceAnalysisEngine(aeDesc, ((UimaContextAdmin) c).getResourceManager(), null);
        } else {
            ae = UIMAFramework.produceAnalysisEngine(aeDesc);
        }
        return ae;
    }

    public static <T extends Resource> List<T> createResourceList(Object o, Class<T> type) {
        List<T> resources = null;
        if (o instanceof String) {
            String description = (String) o;
            Yaml yaml = new Yaml();
            @SuppressWarnings("unchecked")
            List<Map<String, String>> ao = (List<Map<String, String>>) yaml.load(description);
            resources = createResourceList(ao, type);
        } else {
            // TODO: Remove this deprecated call at some point in time
            String[] expListenerNames = (String[]) o;
            resources = createResourceList(expListenerNames, type);
        }
        return resources;
    }

    @Deprecated
    private static <T extends Resource> List<T> createResourceList(String[] names, Class<T> type) {
        System.err.println(
                "The bang syntax (!) for resource creation is deprecated please use the string (|) syntax instead: 'parameter: |\\n - [inherit|class]: fully.qualified.name'");
        System.err.println(" Offending configuration: " + Arrays.toString(names));
        List<T> resources = Lists.newArrayList();
        for (String name : names) {
            try {
                ResourceHandle handle = buildHandleFromString(name);
                resources.add(buildResource(handle, type));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return resources;
    }

    private AbstractExperimentPersistenceProvider newPersistenceProvider(AnyObject config)
            throws ResourceInitializationException {
        AnyObject pprovider = config.getAnyObject("persistence-provider");
        if (pprovider == null) {
            return new DefaultExperimentPersistenceProvider();
        }
        try {
            return initializeResource(config, "persistence-provider", AbstractExperimentPersistenceProvider.class);
        } catch (Exception e) {
            throw new ResourceInitializationException(
                    ResourceInitializationException.ERROR_INITIALIZING_FROM_DESCRIPTOR,
                    new Object[] { "persistence-provider", config }, e);
        }
    }

}