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

org.integratedmodelling.engine.ModelFactory Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (C) 2007, 2015:
 * 
 * - Ferdinando Villa  - integratedmodelling.org - any
 * other authors listed in @author annotations
 *
 * All rights reserved. This file is part of the k.LAB software suite, meant to enable
 * modular, collaborative, integrated development of interoperable data and model
 * components. For details, see http://integratedmodelling.org.
 * 
 * This program is free software; you can redistribute it and/or modify it under the terms
 * of the Affero General Public License Version 3 or 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 Affero General Public License for more details.
 * 
 * You should have received a copy of the Affero General Public License along with this
 * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite
 * 330, Boston, MA 02111-1307, USA. The license is also available at:
 * https://www.gnu.org/licenses/agpl.html
 *******************************************************************************/
package org.integratedmodelling.engine;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.integratedmodelling.api.errormanagement.ICompileError;
import org.integratedmodelling.api.errormanagement.ICompileInfo;
import org.integratedmodelling.api.errormanagement.ICompileWarning;
import org.integratedmodelling.api.lang.INamespaceQualified;
import org.integratedmodelling.api.lang.IParsingScope;
import org.integratedmodelling.api.modelling.IActiveDirectObservation;
import org.integratedmodelling.api.modelling.IClassification;
import org.integratedmodelling.api.modelling.IClassifyingObserver;
import org.integratedmodelling.api.modelling.IDataSource;
import org.integratedmodelling.api.modelling.IDirectObserver;
import org.integratedmodelling.api.modelling.IExtent;
import org.integratedmodelling.api.modelling.IFunctionCall;
import org.integratedmodelling.api.modelling.IModel;
import org.integratedmodelling.api.modelling.IModelObject;
import org.integratedmodelling.api.modelling.INamespace;
import org.integratedmodelling.api.modelling.INumericObserver;
import org.integratedmodelling.api.modelling.IObservableSemantics;
import org.integratedmodelling.api.modelling.IObserver;
import org.integratedmodelling.api.modelling.IPresenceObserver;
import org.integratedmodelling.api.modelling.IScale;
import org.integratedmodelling.api.modelling.storage.IDataset;
import org.integratedmodelling.api.modelling.storage.IStorage;
import org.integratedmodelling.api.monitoring.IKnowledgeLifecycleListener;
import org.integratedmodelling.api.monitoring.IMonitor;
import org.integratedmodelling.api.runtime.IContext;
import org.integratedmodelling.api.space.IGrid;
import org.integratedmodelling.api.space.IGridMask;
import org.integratedmodelling.api.space.IShape;
import org.integratedmodelling.api.space.ISpatialExtent;
import org.integratedmodelling.api.space.ISpatialIndex;
import org.integratedmodelling.api.time.ITemporalExtent;
import org.integratedmodelling.api.time.ITimeDuration;
import org.integratedmodelling.api.time.ITimeInstant;
import org.integratedmodelling.common.classification.Classification;
import org.integratedmodelling.common.configuration.KLAB;
import org.integratedmodelling.common.kim.KIMDirectObserver;
import org.integratedmodelling.common.kim.KIMFunctionCall;
import org.integratedmodelling.common.kim.KIMScope;
import org.integratedmodelling.common.space.IGeometricShape;
import org.integratedmodelling.common.storage.BooleanStorage;
import org.integratedmodelling.common.storage.ConceptStorage;
import org.integratedmodelling.common.storage.NumberStorage;
import org.integratedmodelling.common.storage.ProbabilityStorage;
import org.integratedmodelling.common.vocabulary.ObservableSemantics;
import org.integratedmodelling.engine.geospace.extents.SpaceExtent;
import org.integratedmodelling.engine.geospace.extents.SpatialIndex;
import org.integratedmodelling.engine.geospace.gis.ThinklabRasterizer;
import org.integratedmodelling.engine.geospace.literals.ShapeValue;
import org.integratedmodelling.engine.modelling.datasources.ConstantDataSource;
import org.integratedmodelling.engine.modelling.kbox.ModelKbox;
import org.integratedmodelling.engine.modelling.kbox.ObservationKbox;
import org.integratedmodelling.engine.modelling.runtime.Scale;
import org.integratedmodelling.engine.modelling.runtime.Subject;
import org.integratedmodelling.engine.time.functions.TIME;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabInternalErrorException;
import org.integratedmodelling.exceptions.KlabRuntimeException;

public class ModelFactory extends org.integratedmodelling.common.kim.ModelFactory {

	class EngineKIMContext extends KIMScope {

		@Override
		protected KIMScope newInstance() {
			return new EngineKIMContext();
		}

		@Override
		public void onError(ICompileError error) {
			KLAB.error(error.toString());
		}

		@Override
		protected void onWarning(ICompileWarning error) {
			// Env.logger.warn(error.toString());
		}

		@Override
		protected void onInfo(ICompileInfo error) {
			// Env.logger.info(error.toString());
		}
	}

	class KnowledgeListener implements IKnowledgeLifecycleListener {

		Map recheckModelNS = new HashMap<>();
		Map recheckObservationNS = new HashMap<>();

		@Override
		public void objectDefined(IModelObject object) {

			Integer storingNamespace = recheckModelNS.get(object.getNamespace().getId());
			Integer storingObservation = recheckObservationNS.get(object.getNamespace().getId());

			if (object instanceof IModel && !object.isInactive() && storingNamespace != null && storingNamespace > 0) {

				/*
				 * do not store anything coming from remote projects - just use
				 * them when they're online.
				 */
				if (!(object.getNamespace().getProject().isRemote())) {

					boolean store = true;

					try {
						if (storingNamespace == 2) {
							store = ModelKbox.get().hasModel(object.getName());
						}
						if (store) {
//							ModelKbox.get().store(object);
                            ModelKbox.get().store(object);
						}
					} catch (KlabException e) {
						KLAB.error("error storing model: " + e);
					}

				}
			}

			if (object instanceof IDirectObserver && !object.isInactive() && storingObservation != null
					&& storingObservation > 0) {

				/*
				 * goes in the searchable observation kbox. We piggyback on the
				 * model kbox to handle the namespace synchronization.
				 */
				if (!(object.getNamespace().getProject().isRemote())) {

					boolean store = true;

					try {
						if (storingObservation == 2) {
							store = ObservationKbox.get().hasObservation(object.getName());
						}
						if (store) {
							ObservationKbox.get().store(object);
						}
					} catch (KlabException e) {
						KLAB.error("error storing observation: " + e);
					}
				}

			}
		}

		@Override
		public void namespaceDeclared(INamespace namespace) {

			if (!namespace.hasErrors()) {

				try {
					int cmodel = ModelKbox.get().removeIfOlder(namespace);
					if (cmodel > 0) {
						recheckModelNS.put(namespace.getId(), cmodel);
					}
				} catch (Exception e) {

				}

				try {
					int cobser = ObservationKbox.get().removeIfOlder(namespace);
					if (cobser > 0) {
						recheckObservationNS.put(namespace.getId(), cobser);
					}
				} catch (Exception e) {

				}
			}

		}

		@Override
		public void namespaceDefined(INamespace namespace) {

			Integer storingNamespace = recheckModelNS.remove(namespace.getId());
			Integer storingObservation = recheckObservationNS.remove(namespace.getId());

			if (storingNamespace != null && storingNamespace > 0 && !(namespace.getProject().isRemote())) {

				try {
//					ModelKbox.get().store(namespace);
                    ModelKbox.get().store(namespace);
				} catch (Exception e) {
					KLAB.error("error storing knowledge", e);
				}
			}

			if (storingObservation != null && storingObservation > 0 && !(namespace.getProject().isRemote())) {

				try {
					ObservationKbox.get().store(namespace);
				} catch (Exception e) {
					KLAB.error("error storing knowledge", e);
				}
			}
		}
	}

	@Override
	public IParsingScope getRootParsingContext() {
		return new EngineKIMContext();
	}

	@SuppressWarnings("javadoc")
	public ModelFactory() {
		addKnowledgeLifecycleListener(new KnowledgeListener());
	}

	@Override
	public IStorage createStorage(IObserver observer, IScale scale, IDataset dataset, boolean isDynamic,
			boolean isProbabilistic) {

		IObservableSemantics observable = new ObservableSemantics((ObservableSemantics) (observer.getModel() == null ? observer.getObservable()
				: observer.getModel().getObservable()));

		((ObservableSemantics) observable).setObserver(observer);

		if (observer instanceof INumericObserver && ((INumericObserver) observer).getDiscretization() == null) {
			return new NumberStorage(observable, scale, ((INumericObserver) observer).getDiscretization(), dataset,
					isDynamic);
		} else if (observer instanceof IClassifyingObserver || (observer instanceof INumericObserver
				&& ((INumericObserver) observer).getDiscretization() != null)) {
			IClassification classif = (observer instanceof IClassifyingObserver)
					? ((IClassifyingObserver) observer).getClassification()
					: ((INumericObserver) observer).getDiscretization();
			if (classif != null) {
			    // extra safety
			    ((Classification)classif).initialize();
			}
			return isProbabilistic ? new ProbabilityStorage(observable, scale, dataset, isDynamic, classif)
					: new ConceptStorage(observable, scale, dataset, isDynamic, classif);
		} else if (observer instanceof IPresenceObserver) {
			return new BooleanStorage(observable, scale, dataset, isDynamic);
		}

		throw new KlabRuntimeException("don't know how to create storage for observer " + observer);
	}

	@Override
	public IActiveDirectObservation createSubject(IDirectObserver observer, IContext context, IActiveDirectObservation contextObservation,
			IMonitor monitor) throws KlabException {
		return getSubjectByMetadata(observer.getObservable(), context, contextObservation, observer.getNamespace(),
				sanitizeScale(observer.getCoverage(monitor)), observer.getId(), monitor);
	}

	public IScale sanitizeScale(IScale scale) throws KlabException {
		List exts = new ArrayList<>();
		for (IExtent e : scale) {
			exts.add(sanitizeExtent(e));
		}
		return new Scale(exts);
	}

	@Override
	public IScale createScale(Collection definition, IMonitor monitor) {
		try {
			List exts = new ArrayList<>();
			for (IFunctionCall f : definition) {
				Object o = callFunction(f, monitor, null);
				if (!(o instanceof IExtent)) {
					throw new KlabRuntimeException("function call " + f + " did not produce an extent");
				}
				if (o instanceof INamespaceQualified) {
					((INamespaceQualified) o).setNamespace(((KIMFunctionCall) f).getNamespace());
				}
				exts.add((IExtent) o);
			}
			return new Scale(exts);
		} catch (KlabException e) {
			throw new KlabRuntimeException(e);
		}
	}

	/**
	 * Return a new subject generator whose scale has the passed forcings
	 * applied.
	 *
	 * @param observer
	 * @param forcings
	 * @return a new subject generator whose scale has the passed forcings
	 *         applied
	 * @throws KlabException
	 */
	public static IDirectObserver forceScale(IDirectObserver observer, IMonitor monitor, Collection forcings)
			throws KlabException {
		IScale oldScale = Scale.sanitize(observer.getCoverage(monitor));
		List forcedExtents = org.integratedmodelling.common.model.runtime.Scale.forceExtents(oldScale,
				forcings.toArray(new IExtent[forcings.size()]));
		IScale newScale = new Scale(forcedExtents.toArray(new IExtent[forcedExtents.size()]));
		return ModelFactory.createDirectObserver(observer.getObservable().getType(), observer.getId(),
				observer.getNamespace(), monitor, newScale);
	}

	/**
	 * Return a direct observer that's guaranteed to have engine-grade scale and
	 * observer implementations.
	 * 
	 * Should be less necessary now, or even completely unnecessary, but testing
	 * that is for another day.
	 * 
	 * TODO does not work!
	 * 
	 * @param observer
	 * @return an engine-safe copy of the direct observer
	 */
	public static IDirectObserver sanitizeDirectObserver(IDirectObserver observer) {
		return new KIMDirectObserver((KIMDirectObserver) observer);
	}

	/**
	 * The main entry point.
	 *
	 * @param observable
	 * @param namespace
	 * @param scale
	 * @param newSubjectId
	 * @param monitor
	 * @return a new subject
	 * @throws KlabException
	 */
	public static Subject getSubjectByMetadata(IObservableSemantics observable, IContext context, IActiveDirectObservation contextObservation, INamespace namespace, IScale scale,
			String newSubjectId, IMonitor monitor) throws KlabException {

		Subject result;
		Constructor constructor;

		Class agentClass = KLAB.MMANAGER.getSubjectClass(observable.getType());
		if (agentClass == null) {
			agentClass = Subject.class;
		}

		try {
			constructor = agentClass.getConstructor(IObservableSemantics.class,
			        IActiveDirectObservation.class,
					IScale.class, IContext.class, INamespace.class, String.class, IMonitor.class);
		} catch (Exception e) {
			throw new KlabInternalErrorException("No viable constructor found for Java class '"
					+ agentClass.getCanonicalName() + "' for agent type '" + observable.getFormalName() + "'");
		}

		try {
			result = (Subject) constructor.newInstance(observable, contextObservation, scale, context, namespace, newSubjectId, monitor);
		} catch (Exception e) {
			throw new KlabRuntimeException("Unable to generate new instance of Java class '"
					+ agentClass.getCanonicalName() + "' for agent type '" + observable.getFormalName() + "'");
		}

		return result;

	}

	@Override
	public IDataSource createConstantDataSource(Object inlineValue) {
		return new ConstantDataSource(inlineValue);
	}

//	@Override
//	public Object wrapForAction(Object object) {
//		if (object instanceof Subject) {
//			return new ActionSubject((Subject) object);
//		} else if (object instanceof SpaceExtent) {
//			return new ActionSpace((SpaceExtent) object);
//		}
//		return super.wrapForAction(object);
//	}

	@Override
	public ISpatialIndex getSpatialIndex(ISpatialExtent space) {
		return new SpatialIndex(space);
	}

	@SuppressWarnings("unchecked")
	@Override
	public  T adapt(Object toAdapt, Class desiredClass) {
		return defaultAdapt(toAdapt, desiredClass);
	}

	@Override
	public void cleanNamespaceArtifacts(String namespaceId) throws KlabException {
		// clean kboxes
//		ModelKbox.get().clearNamespace(namespaceId);
        ModelKbox.get().clearNamespace(namespaceId);
		ObservationKbox.get().clearNamespace(namespaceId);
	}

	@Override
	public IExtent sanitizeExtent(IExtent extent) throws KlabException {
		if (extent instanceof ISpatialExtent && !(extent instanceof SpaceExtent)) {
			extent = new SpaceExtent((IGeometricShape) ((ISpatialExtent) extent).getShape(),
					((ISpatialExtent) extent).getGrid());
		} else if (extent instanceof ITemporalExtent) {
			ITemporalExtent time = (ITemporalExtent) extent;
			if (!time.getClass().getCanonicalName().contains(".engine.")) {
				ITimeInstant start = time.getStart();
				ITimeInstant end = time.getEnd();
				ITimeDuration step = time.getStep();
				Map map = new HashMap<>();
				if (start != null) {
					map.put("start", start.getMillis());
				}
				if (end != null) {
					map.put("end", end.getMillis());
				}
				if (step != null) {
					map.put("step", step.getMilliseconds());
				}
				extent = new TIME().eval(map, KLAB.ENGINE.getMonitor());
			}

		}
		return extent;
	}
	
    @Override
    public IGridMask createMask(Collection shape, IGrid grid) throws KlabException {
        List shapes = new ArrayList<>();
        for (IShape s : shape) {
            if (s instanceof ShapeValue) {
                shapes.add((ShapeValue)s);
            }
        }
        return ThinklabRasterizer.createMask(shapes, grid);
    }

    @Override
    public IGridMask createMask(IShape shape, IGrid grid) throws KlabException {
        return ThinklabRasterizer.createMask((ShapeValue)shape, grid);
    }

    @Override
    public IGridMask addToMask(IShape shape, IGridMask mask) throws KlabException {
        return ThinklabRasterizer.addToMask((ShapeValue) shape, mask);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy